diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..8674f62
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,18 @@
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.{md,yml,yaml}]
+indent_size = 2
+
+[*.{svg,png,jpg,pdf,gif}]
+insert_final_newline = false
+
+[*.{ts,qm}]
+insert_final_newline = false
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
new file mode 100644
index 0000000..62e0fee
--- /dev/null
+++ b/.git-blame-ignore-revs
@@ -0,0 +1,4 @@
+# This commit applies ruff format + ruff check --fix to all Python files.
+# Use git blame --ignore-revs-file .git-blame-ignore-revs to skip it.
+# When reviewing the PR, append ?w=1 to the diff URL to hide whitespace changes.
+7cb8760cc1e5be808f61bbffcd8bb239e609352d
diff --git a/.gitattributes b/.gitattributes
index bdb0cab..3709ca7 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,17 +1,21 @@
-# Auto detect text files and perform LF normalization
-* text=auto
-
-# Custom for Visual Studio
-*.cs diff=csharp
-
-# Standard to msysgit
-*.doc diff=astextplain
-*.DOC diff=astextplain
-*.docx diff=astextplain
-*.DOCX diff=astextplain
-*.dot diff=astextplain
-*.DOT diff=astextplain
-*.pdf diff=astextplain
-*.PDF diff=astextplain
-*.rtf diff=astextplain
-*.RTF diff=astextplain
+* text=auto eol=lf
+*.py text diff=python
+*.md text diff=markdown
+*.svg text
+*.ui text
+*.xml text
+*.yml text
+*.yaml text
+*.toml text
+*.cfg text
+*.ini text
+*.ts text
+*.qm binary
+*.png binary
+*.jpg binary
+*.gif binary
+*.pdf binary
+*.FCStd binary
+*.step binary
+*.stp binary
+*.dxf binary
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..d08bfbb
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,18 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ day: "monday"
+ commit-message:
+ prefix: "ci"
+
+ - package-ecosystem: "pip"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ day: "monday"
+ commit-message:
+ prefix: "chore"
+ open-pull-requests-limit: 3
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..634cf2d
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,45 @@
+name: CI
+
+on:
+ push:
+ branches: [master, main]
+ pull_request:
+ branches: [master, main]
+ schedule:
+ - cron: "0 6 * * 1" # every Monday 06:00 UTC
+
+jobs:
+ ruff:
+ name: Ruff (lint + format)
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: astral-sh/setup-uv@v6
+ with:
+ enable-cache: true
+ - uses: astral-sh/ruff-action@v3
+ with:
+ args: check
+ - uses: astral-sh/ruff-action@v3
+ with:
+ args: format --check
+
+ pre-commit:
+ name: Pre-commit
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-python@v5
+ with:
+ python-version: "3.12"
+ - uses: pre-commit/action@v3.0.1
+
+ types:
+ name: Type check (ty)
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - uses: astral-sh/setup-uv@v6
+ with:
+ enable-cache: true
+ - run: uvx ty check
diff --git a/.gitignore b/.gitignore
index 06703cd..29b686b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,8 +18,19 @@ $RECYCLE.BIN/
# Windows shortcuts
*.lnk
-# Python executable
+# Python
*.pyc
+__pycache__/
+
+# Tooling caches
+.ruff_cache/
+.pre-commit/
+.uv/
+
+# Editor
+*.swp
+*.swo
+*~
# =========================
# Operating System Files
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..bbfcf82
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,34 @@
+repos:
+ - repo: https://github.com/astral-sh/ruff-pre-commit
+ rev: v0.15.8
+ hooks:
+ - id: ruff
+ args: [--fix, --exit-non-zero-on-fix]
+ - id: ruff-format
+
+ - repo: local
+ hooks:
+ - id: ty
+ name: ty
+ entry: uvx ty check
+ language: system
+ types: [python]
+ pass_filenames: false
+
+ - repo: https://github.com/pre-commit/pre-commit-hooks
+ rev: v5.0.0
+ hooks:
+ - id: check-added-large-files
+ args: [--maxkb=500]
+ - id: check-case-conflict
+ - id: check-merge-conflict
+ - id: check-toml
+ - id: check-xml
+ - id: check-yaml
+ - id: debug-statements
+ - id: detect-private-key
+ - id: end-of-file-fixer
+ - id: mixed-line-ending
+ args: [--fix=lf]
+ - id: trailing-whitespace
+ args: [--markdown-linebreak-ext=md]
diff --git a/Init.py b/Init.py
index e2cf6fc..4eaa234 100644
--- a/Init.py
+++ b/Init.py
@@ -1,29 +1,29 @@
-#-*- coding: utf-8 -*-
-#****************************************************************************
-#* *
-#* Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
-#* 3D exporter for FreeCAD *
-#* Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
-#* Copyright (c) 2015 *
-#* Maurice easyw@katamail.com *
-#* *
-#* Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
-#* *
+# ****************************************************************************
+# * *
+# * Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
+# * 3D exporter for FreeCAD *
+# * Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
+# * Copyright (c) 2015 *
+# * Maurice easyw@katamail.com *
+# * *
+# * Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
+# * *
+
+import FreeCAD
# two options for IDF added by Milos Koutny (12-Feb-2010)
-#FreeCAD.addImportType("Kicad pcb board/mod File Type (*.kicad_pcb *.emn *.kicad_mod)","kicadStepUptools")
+# FreeCAD.addImportType("Kicad pcb board/mod File Type (*.kicad_pcb *.emn *.kicad_mod)","kicadStepUptools")
# ___ver___ = "6.0.4.5"
## idf import dropped
-#FreeCAD.addImportType("Kicad pcb board/mod File Type (*.kicad_pcb *.kicad_mod)","kicadStepUptools")
-FreeCAD.addImportType("Kicad pcb board File Type (*.kicad_pcb)","kicadStepUptools")
-FreeCAD.addImportType("Kicad pcb mod File Type (*.kicad_mod)","kicadStepUptools")
+# FreeCAD.addImportType("Kicad pcb board/mod File Type (*.kicad_pcb *.kicad_mod)","kicadStepUptools")
+FreeCAD.addImportType("Kicad pcb board File Type (*.kicad_pcb)", "kicadStepUptools")
+FreeCAD.addImportType("Kicad pcb mod File Type (*.kicad_mod)", "kicadStepUptools")
-FreeCAD.addImportType("zip of STEP/FCStd File Type (*.zip)","ZipStepImport")
+FreeCAD.addImportType("zip of STEP/FCStd File Type (*.zip)", "ZipStepImport")
# using faithful old legacy dxf v1.4.0
# FreeCAD.addImportType("DXF Legacy Type (*.dxf)","_DXF_Import")
-import FreeCAD
-#FreeCAD.addImportType("IDF emp File Type (*.emp)","Import_Emp")
+# FreeCAD.addImportType("IDF emp File Type (*.emp)","Import_Emp")
diff --git a/InitGui.py b/InitGui.py
index 85efb33..e617fb6 100644
--- a/InitGui.py
+++ b/InitGui.py
@@ -1,62 +1,58 @@
-# -*- coding: utf-8 -*-
-#****************************************************************************
-#* *
-#* Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
-#* 3D exporter for FreeCAD *
-#* Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
-#* Copyright (c) 2015 *
-#* Maurice easyw@katamail.com *
-#* *
-#* Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
-#* *
-
-ksu_wb_version='v 11.08.2'
+# ****************************************************************************
+# * *
+# * Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
+# * 3D exporter for FreeCAD *
+# * Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
+# * Copyright (c) 2015 *
+# * Maurice easyw@katamail.com *
+# * *
+# * Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
+# * *
+
+ksu_wb_version = "v 11.08.2"
global myurlKWB, ksuWBpath
-myurlKWB='https://github.com/easyw/kicadStepUpMod'
+myurlKWB = "https://github.com/easyw/kicadStepUpMod"
global mycommitsKWB
-mycommitsKWB=729 # NB all the commits must have commit message ending with _cmtnum=nnn
+mycommitsKWB = 729 # NB all the commits must have commit message ending with _cmtnum=nnn
# cmtnum=720'
global verKSU
-verKSU="12.7.3"
-
-import FreeCAD, FreeCADGui, Part, os, sys
-import re, time
-# import Materials
+verKSU = "12.7.3"
+import os
+import re
+import sys
+import time
-if (sys.version_info > (3, 0)): #py3
- import urllib
- from urllib import request, error #URLError, HTTPError
-else: #py2
- import urllib2
- from urllib2 import Request, urlopen, URLError, HTTPError
+import FreeCAD
+import FreeCADGui
+# import Materials
import ksu_locator
from kicadStepUpCMD import *
-
ksuWBpath = os.path.dirname(ksu_locator.__file__)
-#sys.path.append(ksuWB + '/Gui')
-ksuWB_icons_path = os.path.join( ksuWBpath, 'Resources', 'icons')
-ksuWB_ui_path = os.path.join( ksuWBpath, 'Resources','ui' )
-ksuWB_trans_path = os.path.join( ksuWBpath, 'translations')
+# sys.path.append(ksuWB + '/Gui')
+ksuWB_icons_path = os.path.join(ksuWBpath, "Resources", "icons")
+ksuWB_ui_path = os.path.join(ksuWBpath, "Resources", "ui")
+ksuWB_trans_path = os.path.join(ksuWBpath, "translations")
FreeCADGui.addLanguagePath(ksuWB_trans_path)
FreeCADGui.updateLocale()
global main_ksu_Icon
-main_ksu_Icon = os.path.join( ksuWB_icons_path , 'kicad-StepUp-tools-WB.svg')
+main_ksu_Icon = os.path.join(ksuWB_icons_path, "kicad-StepUp-tools-WB.svg")
+
from PySide import QtGui
-from threading import Timer
import hlp
-header_txt="""kicad StepUp version """+verKSU+"""
"""
-help_t = header_txt+hlp.help_txt
-#try:
+header_txt = """kicad StepUp version """ + verKSU + """
"""
+help_t = header_txt + hlp.help_txt
+
+# try:
# from FreeCADGui import Workbench
-#except ImportError as e:
+# except ImportError as e:
# FreeCAD.Console.PrintWarning("error")
# class CalendarPage:
# def __init__(self):
@@ -68,48 +64,47 @@
# def loadSettings(self):
# print ("loadSettings")
-class kSU_MainPrefPage:
+class kSU_MainPrefPage:
def selectDirectory(self):
- from PySide import QtGui, QtCore
selected_directory = QtGui.QFileDialog.getExistingDirectory()
# Use the selected directory...
- print ('selected_directory:', selected_directory)
+ print("selected_directory:", selected_directory)
def __init__(self, parent=None):
- from PySide import QtGui, QtCore
- import os, hlp, sys
+
+ import hlp
+
# os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1"
# os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
# os.environ["QT_SCALE_FACTOR"] = "1"
global ksuWBpath
+
def reload_lib(lib):
- if (sys.version_info > (3, 0)):
- import importlib
- importlib.reload(lib)
- else:
- reload (lib)
+ import importlib
- print ("Created kSU Auxiliary Pref page")
+ importlib.reload(lib)
+
+ print("Created kSU Auxiliary Pref page")
# https://stackoverflow.com/questions/71852282/qt-designer-not-playing-nicely-with-windows-display-scaling
# https://stackoverflow.com/questions/20464814/changing-dpi-scaling-size-of-display-make-qt-applications-font-size-get-rendere
- #help_t = hlp.help_txt
- #reload_lib(hlp)
- header_txt="""kicad StepUp version """+verKSU+"""
"""
- help_t = header_txt+hlp.help_txt
+ # help_t = hlp.help_txt
+ # reload_lib(hlp)
+ header_txt = """kicad StepUp version """ + verKSU + """
"""
+ help_t = header_txt + hlp.help_txt
self.form = QtGui.QWidget()
- #self.form.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
+ # self.form.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)
# mw1 = FreeCADGui.getMainWindow()
# print ('physical DPI',mw1.screen().physicalDotsPerInch())
# print ('logical DPI',mw1.screen().logicalDotsPerInch())
- print ('physical aux page',self.form.physicalDpiX())
- print ('logical aux page',self.form.logicalDpiX())
- scaling = self.form.logicalDpiX() / self.form.physicalDpiX() # /96.0 # self is of QWidget
- print ('scaling aux page',scaling)
+ print("physical aux page", self.form.physicalDpiX())
+ print("logical aux page", self.form.logicalDpiX())
+ scaling = self.form.logicalDpiX() / self.form.physicalDpiX() # /96.0 # self is of QWidget
+ print("scaling aux page", scaling)
# print(self.form.screen.devicePixelRatio())
self.form.setWindowTitle("kSU 'Help Tips'")
self.form.mainLayout = QtGui.QGridLayout(self.form)
@@ -124,274 +119,382 @@ def reload_lib(lib):
self.form.groupBoxLayout.addWidget(self.form.textEdit)
self.form.mainLayout.addWidget(self.form.groupBox, 0, 0, 1, 1)
# Button UI
- add_button=False
+ add_button = False
if add_button:
- self.form.btn = QtGui.QPushButton('Create Folder', self.form.verticalLayoutWidget)
- self.form.btn.setToolTip('This creates the folders.')
+ self.form.btn = QtGui.QPushButton("Create Folder", self.form.verticalLayoutWidget)
+ self.form.btn.setToolTip("This creates the folders.")
self.form.btn.resize(self.form.btn.sizeHint())
self.form.btn.move(5, 60)
self.form.btn.clicked.connect(self.selectDirectory)
self.form.verticalLayout.addWidget(self.form.btn)
def saveSettings(self):
- print ("saveSettings Helper")
+ print("saveSettings Helper")
import SaveSettings
+
SaveSettings.update_ksuGui()
def loadSettings(self):
- print ("loadSettings Helper")
- prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetString('prefix3d_1')+'/'
- print('KISYS3DMOD assigned to: ', prefs)
+ print("loadSettings Helper")
+ prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetString("prefix3d_1") + "/"
+ print("KISYS3DMOD assigned to: ", prefs)
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- #if prefs.GetContents() is not None:
+ # if prefs.GetContents() is not None:
# for p in prefs.GetContents():
# print (p)
print(FreeCAD.getUserAppDataDir())
-class KiCadStepUpWB ( Workbench ):
+
+class KiCadStepUpWB(Workbench):
from TranslateUtils import translate
+
global main_ksu_Icon, ksu_wb_version, myurlKWB, mycommitsKWB, verKSU
global ksuWB_ui_path, kSU_MainPrefPage, ksuWB_icons_path
-
+
"KiCadStepUp WB object"
Icon = main_ksu_Icon
- #Icon = ":Resources/icons/kicad-StepUp-tools-WB.svg"
+ # Icon = ":Resources/icons/kicad-StepUp-tools-WB.svg"
MenuText = translate("KiCadStepUpWB", "KiCadStepUp")
ToolTip = translate("KiCadStepUpWB", "KiCadStepUp workbench")
-
+
def GetClassName(self):
return "Gui::PythonWorkbench"
-
+
def Initialize(self):
- import kicadStepUpCMD, sys
global pref_page
- pref_page = True # False #True #
+ pref_page = True # False #True #
import FreeCADGui
+
from TranslateUtils import translate
- submenu = ['demo.kicad_pcb','d-pak.kicad_mod', 'demo-sketch.FCStd', 'demo.step',\
- 'footprint-template.FCStd', 'footprint-Edge-template.FCStd', 'footprint-template-roundrect-polylines.FCStd',\
- 'footprint-RF-antenna.FCStd', 'footprint-RF-antenna-w-solder-Mask.FCStd', 'RF-antenna-dxf.dxf', \
- 'complex-Polyline-footprint.FCStd', 'footprint-complex-arc-pads.FCStd', 'hollow-pad.FCStd', \
- 'footprint-SPU0410LR5H.FCStd','WaveguideAntenna-RF-fp.FCStd', 'Notch-RF-filter-wNT-fp.FCStd', \
- 'Microstrip-RF-filter-fp.FCStd', 'Splitter-RF-fp.FCStd', 'FH36W-11S-0.3SHW_1x11-FlatCable.FCStd', \
- 'kicadStepUp-cheat-sheet.pdf', 'kicad-3D-to-MCAD.pdf', 'Generating-a-KiCAD-footprint-and-Model-from-3D-Step-Data.pdf', \
- 'ECAD-MCAD-collaboration.pdf']
- dirs = self.ListDemos()
-
- #self.appendToolbar(translate("Toolbar", "ksu Tools"), ["ksuTools"])
- self.appendToolbar(translate("Toolbar", "ksu Tools"), ["ksuToolsEditPrefs","ksuTools","ksuToolsOpenBoard","ksuToolsImportFootprint",\
- "ksuToolsExportModel","ksuToolsPushPCB","ksuToolsFootprintGen","Separator","ksuToolsAddTracks","ksuToolsAddSilks","Separator",\
- "ksuToolsCollisions","ksuToolsImport3DStep","ksuToolsExport3DStep","ksuToolsMakeUnion",\
- "ksuToolsMakeCompound", "ksuToolsUnion", "ksuToolsSimpleCopy", "ksuToolsDeepCopy", "ksuToolsColoredClone",\
- "ksuToolsColoredBinder", "ksuToolsReLinkBinder", "ksuToolsCheckSolid"])
- #, "ksuToolsPushMoved","ksuToolsSync3DModels"])
- self.appendToolbar(translate("Toolbar", "ksu Sketching"), ["ksuTools3D2D", "ksuTools2D2Sketch", "ksuTools2DtoFace",\
- "ksuToolsLoopSelection","ksuToolsEdges2Sketch","ksuToolsSelection2Edges","ksuToolsMoveSketch","ksuToolsOffset2D","ksuToolsExtrude","Create_BoundBox","ksuToolsMergeSketches",\
- "ksuToolsSimplifySketck", "ksuToolsBsplineNormalize", "ksuToolsConstrainator", "ksuToolsSkValidate", "ksuToolsDiscretize",\
- "ksuToolsContour2Poly", "Arcs2Circles", "approximateCenter"])
- #, "ksuToolsPushMoved","ksuToolsSync3DModels"])
- ksuTB = ["ksuToolsOpenBoard","ksuToolsPushPCB","ksuToolsPushMoved","ksuToolsSync3DModels","ksuToolsPullPCB","ksuToolsPullMoved","ksuAsm2Part",\
- "Separator","ksuToolsGeneratePositions","ksuToolsComparePositions",\
- "Separator","ksuToolsToggleTreeView","Separator","ksuRemoveTimeStamp","ksuRemoveSuffix","Separator","ksuToolsImportFootprint","ksuToolsFootprintGen"]
- #ksuTB.extend(["Separator","ksuToolsAligner","ksuToolsMover","ksuToolsCaliper"])
+ submenu = [
+ "demo.kicad_pcb",
+ "d-pak.kicad_mod",
+ "demo-sketch.FCStd",
+ "demo.step",
+ "footprint-template.FCStd",
+ "footprint-Edge-template.FCStd",
+ "footprint-template-roundrect-polylines.FCStd",
+ "footprint-RF-antenna.FCStd",
+ "footprint-RF-antenna-w-solder-Mask.FCStd",
+ "RF-antenna-dxf.dxf",
+ "complex-Polyline-footprint.FCStd",
+ "footprint-complex-arc-pads.FCStd",
+ "hollow-pad.FCStd",
+ "footprint-SPU0410LR5H.FCStd",
+ "WaveguideAntenna-RF-fp.FCStd",
+ "Notch-RF-filter-wNT-fp.FCStd",
+ "Microstrip-RF-filter-fp.FCStd",
+ "Splitter-RF-fp.FCStd",
+ "FH36W-11S-0.3SHW_1x11-FlatCable.FCStd",
+ "kicadStepUp-cheat-sheet.pdf",
+ "kicad-3D-to-MCAD.pdf",
+ "Generating-a-KiCAD-footprint-and-Model-from-3D-Step-Data.pdf",
+ "ECAD-MCAD-collaboration.pdf",
+ ]
+ self.ListDemos()
+
+ # self.appendToolbar(translate("Toolbar", "ksu Tools"), ["ksuTools"])
+ self.appendToolbar(
+ translate("Toolbar", "ksu Tools"),
+ [
+ "ksuToolsEditPrefs",
+ "ksuTools",
+ "ksuToolsOpenBoard",
+ "ksuToolsImportFootprint",
+ "ksuToolsExportModel",
+ "ksuToolsPushPCB",
+ "ksuToolsFootprintGen",
+ "Separator",
+ "ksuToolsAddTracks",
+ "ksuToolsAddSilks",
+ "Separator",
+ "ksuToolsCollisions",
+ "ksuToolsImport3DStep",
+ "ksuToolsExport3DStep",
+ "ksuToolsMakeUnion",
+ "ksuToolsMakeCompound",
+ "ksuToolsUnion",
+ "ksuToolsSimpleCopy",
+ "ksuToolsDeepCopy",
+ "ksuToolsColoredClone",
+ "ksuToolsColoredBinder",
+ "ksuToolsReLinkBinder",
+ "ksuToolsCheckSolid",
+ ],
+ )
+ # , "ksuToolsPushMoved","ksuToolsSync3DModels"])
+ self.appendToolbar(
+ translate("Toolbar", "ksu Sketching"),
+ [
+ "ksuTools3D2D",
+ "ksuTools2D2Sketch",
+ "ksuTools2DtoFace",
+ "ksuToolsLoopSelection",
+ "ksuToolsEdges2Sketch",
+ "ksuToolsSelection2Edges",
+ "ksuToolsMoveSketch",
+ "ksuToolsOffset2D",
+ "ksuToolsExtrude",
+ "Create_BoundBox",
+ "ksuToolsMergeSketches",
+ "ksuToolsSimplifySketck",
+ "ksuToolsBsplineNormalize",
+ "ksuToolsConstrainator",
+ "ksuToolsSkValidate",
+ "ksuToolsDiscretize",
+ "ksuToolsContour2Poly",
+ "Arcs2Circles",
+ "approximateCenter",
+ ],
+ )
+ # , "ksuToolsPushMoved","ksuToolsSync3DModels"])
+ ksuTB = [
+ "ksuToolsOpenBoard",
+ "ksuToolsPushPCB",
+ "ksuToolsPushMoved",
+ "ksuToolsSync3DModels",
+ "ksuToolsPullPCB",
+ "ksuToolsPullMoved",
+ "ksuAsm2Part",
+ "Separator",
+ "ksuToolsGeneratePositions",
+ "ksuToolsComparePositions",
+ "Separator",
+ "ksuToolsToggleTreeView",
+ "Separator",
+ "ksuRemoveTimeStamp",
+ "ksuRemoveSuffix",
+ "Separator",
+ "ksuToolsImportFootprint",
+ "ksuToolsFootprintGen",
+ ]
+ # ksuTB.extend(["Separator","ksuToolsAligner","ksuToolsMover","ksuToolsCaliper"])
self.appendToolbar(translate("Toolbar", "ksu PushPull"), ksuTB)
- combined_path = '\t'.join(sys.path)
- if 'Manipulator' in combined_path:
- ksuDTB=["ksuToolsAligner","ksuToolsMover","ksuToolsCaliper", "ksuToolsAlignView","Separator","ksuToolsDefeaturingTools"]
+ combined_path = "\t".join(sys.path)
+ if "Manipulator" in combined_path:
+ ksuDTB = [
+ "ksuToolsAligner",
+ "ksuToolsMover",
+ "ksuToolsCaliper",
+ "ksuToolsAlignView",
+ "Separator",
+ "ksuToolsDefeaturingTools",
+ ]
self.appendToolbar(translate("Toolbar", "ksu Design Tools"), ksuDTB)
else:
- ksuDTB=["ksuToolsAlignView"]
+ ksuDTB = ["ksuToolsAlignView"]
self.appendToolbar(translate("Toolbar", "ksu Design Tools"), ksuDTB)
- Hlp_TB = ["ksuToolsToggleTreeView", "Restore_Transparency", "ksuToolsTransparencyToggle", "ksuToolsHighlightToggle",\
- "ksuToolsVisibilityToggle", "ksuToolsVisibilityRestore", "ksuToolsStepImportModeSTD", "ksuToolsStepImportModeComp",\
- "ksuToolsCopyPlacement", "ksuToolsResetPlacement", "ksuToolsResetPartPlacement", "ksuToolsAddToTree",\
- "ksuToolsRemoveFromTree", "ksuToolsRemoveSubTree", "checkSolidExpSTEP"]
- #if 'LinkView' in dir(FreeCADGui):
+ Hlp_TB = [
+ "ksuToolsToggleTreeView",
+ "Restore_Transparency",
+ "ksuToolsTransparencyToggle",
+ "ksuToolsHighlightToggle",
+ "ksuToolsVisibilityToggle",
+ "ksuToolsVisibilityRestore",
+ "ksuToolsStepImportModeSTD",
+ "ksuToolsStepImportModeComp",
+ "ksuToolsCopyPlacement",
+ "ksuToolsResetPlacement",
+ "ksuToolsResetPartPlacement",
+ "ksuToolsAddToTree",
+ "ksuToolsRemoveFromTree",
+ "ksuToolsRemoveSubTree",
+ "checkSolidExpSTEP",
+ ]
+ # if 'LinkView' in dir(FreeCADGui):
# Hlp_TB.remove("ksuToolsHighlightToggle")
self.appendToolbar(translate("Toolbar", "ksu Show"), ["ksuToolsTurnTable", "ksuToolsExplode"])
self.appendToolbar(translate("Toolbar", "ksu Helpers"), Hlp_TB)
- #self.appendMenu(translate("Menu", "ksu Tools"), ["ksuTools","ksuToolsEdit"])
- self.appendMenu(translate("Menu", "ksu Tools"), ["ksuTools","ksuToolsEditPrefs","ksuImpDXF","ksuOpDXF","ksuOpEzDXF"])
- self.appendMenu(translate("Menu", "ksu PushPull"), ["ksuToolsOpenBoard","ksuToolsPushPCB","ksuToolsPushMoved","ksuToolsSync3DModels","ksuToolsPullPCB","ksuToolsPullMoved",\
- "Separator","ksuToolsGeneratePositions","ksuToolsComparePositions",\
- "Separator","ksuRemoveTimeStamp","ksuRemoveSuffix",\
- "Separator","ksuToolsImportFootprint","ksuToolsFootprintGen"])
+ # self.appendMenu(translate("Menu", "ksu Tools"), ["ksuTools","ksuToolsEdit"])
+ self.appendMenu(
+ translate("Menu", "ksu Tools"),
+ ["ksuTools", "ksuToolsEditPrefs", "ksuImpDXF", "ksuOpDXF", "ksuOpEzDXF"],
+ )
+ self.appendMenu(
+ translate("Menu", "ksu PushPull"),
+ [
+ "ksuToolsOpenBoard",
+ "ksuToolsPushPCB",
+ "ksuToolsPushMoved",
+ "ksuToolsSync3DModels",
+ "ksuToolsPullPCB",
+ "ksuToolsPullMoved",
+ "Separator",
+ "ksuToolsGeneratePositions",
+ "ksuToolsComparePositions",
+ "Separator",
+ "ksuRemoveTimeStamp",
+ "ksuRemoveSuffix",
+ "Separator",
+ "ksuToolsImportFootprint",
+ "ksuToolsFootprintGen",
+ ],
+ )
self.appendMenu([translate("Menu", "ksu Tools"), translate("Menu", "Demo")], submenu)
-
- #FreeCADGui.addPreferencePage( a2plib.pathOfModule() + '/GuiA2p/ui/a2p_prefs.ui','A2plus' )
+
+ # FreeCADGui.addPreferencePage( a2plib.pathOfModule() + '/GuiA2p/ui/a2p_prefs.ui','A2plus' )
if pref_page:
mw1 = FreeCADGui.getMainWindow()
- scaling = mw1.logicalDpiX() / mw1.physicalDpiX() # /96.0 # self is of QWidget
- print('main win physicalDpiX()',mw1.physicalDpiX())
- print('main win logicalDpiX()',mw1.logicalDpiX())
- if hasattr(mw1,"screen"):
- print('screen physicalDotsPerInch()',mw1.screen().physicalDotsPerInch())
- print('screen logicalDotsPerInch()' ,mw1.screen().logicalDotsPerInch())
- print('scaling main',scaling)
+ scaling = mw1.logicalDpiX() / mw1.physicalDpiX() # /96.0 # self is of QWidget
+ print("main win physicalDpiX()", mw1.physicalDpiX())
+ print("main win logicalDpiX()", mw1.logicalDpiX())
+ if hasattr(mw1, "screen"):
+ print("screen physicalDotsPerInch()", mw1.screen().physicalDotsPerInch())
+ print("screen logicalDotsPerInch()", mw1.screen().logicalDotsPerInch())
+ print("scaling main", scaling)
# print ('physical DPI',mw1.screen().physicalDotsPerInch())
# print ('logical DPI',mw1.screen().logicalDotsPerInch())
-
- FreeCADGui.addPreferencePage(
- ksuWB_ui_path + '/ksu_prefs.ui',
- 'kicadStepUpGui'
- )
- FreeCADGui.addPreferencePage(kSU_MainPrefPage,"kicadStepUpGui")
+
+ FreeCADGui.addPreferencePage(ksuWB_ui_path + "/ksu_prefs.ui", "kicadStepUpGui")
+ FreeCADGui.addPreferencePage(kSU_MainPrefPage, "kicadStepUpGui")
FreeCADGui.addIconPath(ksuWB_icons_path)
- Log ("Loading ksuModule... done\n")
-
+ Log("Loading ksuModule... done\n")
+
def Activated(self):
- # do something here if needed...
- Msg ("KiCadStepUpWB.Activated("+ksu_wb_version+")\n")
- from PySide import QtGui
- import time, sys, os, re
+ # do something here if needed...
+ Msg("KiCadStepUpWB.Activated(" + ksu_wb_version + ")\n")
+ import codecs # utf-8 config parser
+ import os
from os.path import expanduser
- import codecs #utf-8 config parser
- import FreeCAD, FreeCADGui
+
+ import FreeCAD
+
import commits_num
-
+
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
tnow = int(time.time())
oneday = 86400
if pg.IsEmpty():
- pg.SetBool("checkUpdates",1)
- upd=True
- pg.SetInt("updateDaysInterval",1)
- pg.SetInt("lastCheck",tnow-2*oneday)
- pg.SetInt("dockingMode",0)
- interval=True
- FreeCAD.Console.PrintError('new \'check for updates\' feature added!!!\n')
- msg="""
+ pg.SetBool("checkUpdates", 1)
+ upd = True
+ pg.SetInt("updateDaysInterval", 1)
+ pg.SetInt("lastCheck", tnow - 2 * oneday)
+ pg.SetInt("dockingMode", 0)
+ interval = True
+ FreeCAD.Console.PrintError("new 'check for updates' feature added!!!\n")
+ msg = """
new \'check for updates\' feature added!!!
set \'checkUpdates\' to \'False\' to avoid this checking
in \"Tools\", \"Edit Parameters\",
\"Preferences\"->\"Mod\"->\"kicadStepUp\"
"""
- QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
+ QtGui.QApplication.restoreOverrideCursor() # noqa: F823
+ QtGui.QMessageBox.information(None, "Warning", msg)
else:
- upd=pg.GetBool("checkUpdates")
+ upd = pg.GetBool("checkUpdates")
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
if prefs.IsEmpty():
- #if prefs.GetContents() is None:
+ # if prefs.GetContents() is None:
def mk_str(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.encode('utf-8')
- return input
- else: #py2
- if type(input) == unicode:
- input = input.encode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.encode("utf-8")
+ if type(input) == unicode:
+ return input.encode("utf-8")
+ return input
+
def mk_uni(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.decode('utf-8')
- return input
- else: #py2
- if type(input) != unicode:
- input = input.decode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.decode("utf-8")
+ if type(input) != unicode:
+ return input.decode("utf-8")
+ return input
+
##
- FreeCAD.Console.PrintError('Creating first time ksu preferences\n')
- #prefs.SetString('prefix3d_1',make_string(default_prefix3d))
- prefs.SetInt('pcb_color',0)
- prefs.SetString('drill_size',u'0.0')
- prefs.SetBool('make_union',0)
- prefs.SetBool('exp_step',0)
- prefs.SetBool('turntable',0)
- prefs.SetBool('generate_sketch',1)
- prefs.SetBool('asm3_links',1)
- prefs.SetBool('vrml_materials',1)
- prefs.SetBool('mode_virtual',1)
- prefs.SetInt('pcb_placement',0)
- prefs.SetInt('step_exp_mode',0)
- prefs.SetInt('3D_loading_mode',0)
- prefs.SetInt('sketch_constraints',0)
- prefs.SetString('blacklist',u'')
- prefs.SetString('blacklist',u'')
+ FreeCAD.Console.PrintError("Creating first time ksu preferences\n")
+ # prefs.SetString('prefix3d_1',make_string(default_prefix3d))
+ prefs.SetInt("pcb_color", 0)
+ prefs.SetString("drill_size", "0.0")
+ prefs.SetBool("make_union", 0)
+ prefs.SetBool("exp_step", 0)
+ prefs.SetBool("turntable", 0)
+ prefs.SetBool("generate_sketch", 1)
+ prefs.SetBool("asm3_links", 1)
+ prefs.SetBool("vrml_materials", 1)
+ prefs.SetBool("mode_virtual", 1)
+ prefs.SetInt("pcb_placement", 0)
+ prefs.SetInt("step_exp_mode", 0)
+ prefs.SetInt("3D_loading_mode", 0)
+ prefs.SetInt("sketch_constraints", 0)
+ prefs.SetString("blacklist", "")
+ prefs.SetString("blacklist", "")
home = expanduser("~")
- fname_ksu=home+os.sep+'ksu-config.ini'
- ksu_config_fname=fname_ksu
- if os.path.isfile(ksu_config_fname): # and len (models3D_prefix) == 0:
- FreeCAD.Console.PrintMessage("ksu file \'ksu-config.ini\' exists; getting old config values\n")
- ini_vars=[]
- for i in range (0,20):
- ini_vars.append('-')
- ini_content=[];cfg_content=[]
- #Kicad_Board_elaborated = open(filename, "r").read()[0:]
- #txtFile = __builtin__.open(ksu_config_fname,"r")
- #with io.open(ksu_config_fname,'r', encoding='utf-8') as cfg_file:
- with codecs.open(ksu_config_fname,'r', encoding='utf-8') as cfg_file:
- cfg_content = cfg_file.readlines() #
- #ini_content = cfg_content
+ fname_ksu = home + os.sep + "ksu-config.ini"
+ ksu_config_fname = fname_ksu
+ if os.path.isfile(ksu_config_fname): # and len (models3D_prefix) == 0:
+ FreeCAD.Console.PrintMessage("ksu file 'ksu-config.ini' exists; getting old config values\n")
+ ini_vars = []
+ for i in range(20):
+ ini_vars.append("-")
+ ini_content = []
+ cfg_content = []
+ # Kicad_Board_elaborated = open(filename, "r").read()[0:]
+ # txtFile = __builtin__.open(ksu_config_fname,"r")
+ # with io.open(ksu_config_fname,'r', encoding='utf-8') as cfg_file:
+ with codecs.open(ksu_config_fname, "r", encoding="utf-8") as cfg_file:
+ cfg_content = cfg_file.readlines()
+ # ini_content = cfg_content
cfg_file.close()
for line in cfg_content:
- if re.match(r'^\s*$', line): #empty lines
- FreeCAD.Console.PrintMessage('line empty\n')
+ if re.match(r"^\s*$", line): # empty lines
+ FreeCAD.Console.PrintMessage("line empty\n")
else:
- #ini_content.append(make_unicode(line))
- #print(line)
+ # ini_content.append(make_unicode(line))
+ # print(line)
ini_content.append(line)
+
def find_nm(n):
- n=n.lower()
+ n = n.lower()
return {
- 'prefix3d_1' : 1,
- 'prefix3d_2' : 2,
- 'pcb_color' : 3,
- 'bklist' : 4,
- 'bbox' : 5,
- 'placement' : 6,
- 'virt' : 7,
- 'exportfusing' : 8,
- 'min_drill_size': 9,
- 'last_pcb_path' :10,
- 'last_fp_path' :11,
- 'export_to_step':12,
- 'mat' :13,
- 'spin' :14,
- 'compound' :15,
- 'dkmode' :16,
- 'font_size' :17,
- 'exporting_mode':18,
- 'importing_mode':19,
- }.get(n, 0) # 0 is default if x not found
+ "prefix3d_1": 1,
+ "prefix3d_2": 2,
+ "pcb_color": 3,
+ "bklist": 4,
+ "bbox": 5,
+ "placement": 6,
+ "virt": 7,
+ "exportfusing": 8,
+ "min_drill_size": 9,
+ "last_pcb_path": 10,
+ "last_fp_path": 11,
+ "export_to_step": 12,
+ "mat": 13,
+ "spin": 14,
+ "compound": 15,
+ "dkmode": 16,
+ "font_size": 17,
+ "exporting_mode": 18,
+ "importing_mode": 19,
+ }.get(n, 0) # 0 is default if x not found
+
for line in ini_content:
- line = line.strip() #removes all whitespace at the start and end, including spaces, tabs, newlines and carriage returns
- if len(line)>0:
- if line[0] != ';' and line[0] != '[':
- if '=' in line:
- data = line.split('=', 1)
- #sayw(len(data))
- if len(data) == 1:
- name = mk_uni(data[0].strip())
- key_value = u"" #None
- else:
- name = mk_uni(data[0].strip())
- key_value = mk_uni(data[1].strip())
- # sayerr(len(ini_vars))
- # sayw(str(find_name(name))+' -> '+name+' -> '+key_value)
- ini_vars[find_nm(name)]= key_value
- #print(ini_vars)
+ line = line.strip() # removes all whitespace at the start and end, including spaces, tabs, newlines and carriage returns
+ if len(line) > 0 and line[0] != ";" and line[0] != "[" and "=" in line:
+ data = line.split("=", 1)
+ # sayw(len(data))
+ if len(data) == 1:
+ name = mk_uni(data[0].strip())
+ key_value = "" # None
+ else:
+ name = mk_uni(data[0].strip())
+ key_value = mk_uni(data[1].strip())
+ # sayerr(len(ini_vars))
+ # sayw(str(find_name(name))+' -> '+name+' -> '+key_value)
+ ini_vars[find_nm(name)] = key_value
+ # print(ini_vars)
models3D_prefix = ini_vars[1]
- models3D_prefix2=ini_vars[2]
- FreeCAD.Console.PrintMessage('3D models prefix='+mk_str(models3D_prefix)+'\n')
- FreeCAD.Console.PrintMessage('3D models prefix2='+mk_str(models3D_prefix2)+'\n')
- prefs.SetString('prefix3d_1',mk_str(models3D_prefix.replace('\\','/').rstrip('/')))
- prefs.SetString('prefix3d_2',mk_str(models3D_prefix2.replace('\\','/').rstrip('/')))
- #stop
+ models3D_prefix2 = ini_vars[2]
+ FreeCAD.Console.PrintMessage("3D models prefix=" + mk_str(models3D_prefix) + "\n")
+ FreeCAD.Console.PrintMessage("3D models prefix2=" + mk_str(models3D_prefix2) + "\n")
+ prefs.SetString("prefix3d_1", mk_str(models3D_prefix.replace("\\", "/").rstrip("/")))
+ prefs.SetString("prefix3d_2", mk_str(models3D_prefix2.replace("\\", "/").rstrip("/")))
+ # stop
##
- FreeCAD.Console.PrintError('new \'preferences Page\' added to configure StepUp!!!\n')
- msg="""
+ FreeCAD.Console.PrintError("new 'preferences Page' added to configure StepUp!!!\n")
+ msg = """
new \'preference Page\' added to configure StepUp!!!
old method using ksu-config.ini
@@ -399,88 +502,102 @@ def find_nm(n):
Please have a look at the \'KiCad StepUp tools cheat sheet\' pdf
"""
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
+ QtGui.QMessageBox.information(None, "Warning", msg)
# FreeCADGui.showPreferences("kicadStepUpGui") it cannot launched here until InitGui has run!!!
##
time_interval = pg.GetInt("updateDaysInterval")
if time_interval <= 0:
time_interval = 1
- pg.SetInt("updateDaysInterval",1)
+ pg.SetInt("updateDaysInterval", 1)
nowTimeCheck = int(time.time())
lastTimeCheck = pg.GetInt("lastCheck")
- #print (nowTimeCheck - lastTimeCheck)/(oneday*time_interval)
- if time_interval <= 0 or ((nowTimeCheck - lastTimeCheck)/(oneday*time_interval) >= 1):
+ # print (nowTimeCheck - lastTimeCheck)/(oneday*time_interval)
+ if time_interval <= 0 or ((nowTimeCheck - lastTimeCheck) / (oneday * time_interval) >= 1):
interval = True
- pg.SetInt("lastCheck",tnow)
+ pg.SetInt("lastCheck", tnow)
else:
interval = False
##
if upd and interval:
# check_updates(myurlMWB, mycommitsMWB)
- url=myurlKWB
- commit_nbr=mycommitsKWB
- nbr_commits=commits_num.commitCount('easyw','kicadStepUpMod')
+ url = myurlKWB
+ commit_nbr = mycommitsKWB
+ nbr_commits = commits_num.commitCount("easyw", "kicadStepUpMod")
if int(nbr_commits) == 0:
- FreeCAD.Console.PrintWarning('We failed to get the commit numbers from github.\n')
+ FreeCAD.Console.PrintWarning("We failed to get the commit numbers from github.\n")
else:
- FreeCAD.Console.PrintMessage(url+'-> commits:'+str(nbr_commits)+'\n')
+ FreeCAD.Console.PrintMessage(url + "-> commits:" + str(nbr_commits) + "\n")
delta = int(nbr_commits) - commit_nbr
if delta > 0:
s = ""
- if delta >1:
- s="s"
+ if delta > 1:
+ s = "s"
FreeCAD.Console.PrintError('PLEASE UPDATE "kicadStepUp" WB.\n')
- msg="""
+ msg = (
+ """
PLEASE UPDATE "kicadStepUp" WB.
through \"Tools\" \"Addon manager\" Menu
-
your release is """+str(delta)+""" commit"""+s+""" behind
-
kicadStepUp WB
+
your release is """
+ + str(delta)
+ + """ commit"""
+ + s
+ + """ behind
+
kicadStepUp WB
set \'checkUpdates\' to \'False\' to avoid this checking
in \"Tools\", \"Edit Parameters\",
\"Preferences\"->\"Mod\"->\"kicadStepUp\"
"""
+ )
+
def warn_update_msg():
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
+ QtGui.QMessageBox.information(None, "Warning", msg)
+
if FreeCAD.GuiUp:
# avoiding issue in losing panel & toolbar settings
from PySide import QtCore, QtGui
- dl=1000.0 #ms
- QtCore.QTimer.singleShot(dl,warn_update_msg)
-
+
+ dl = 1000.0 # ms
+ QtCore.QTimer.singleShot(dl, warn_update_msg)
+
else:
- FreeCAD.Console.PrintMessage('the WB is Up to Date\n')
- #
+ FreeCAD.Console.PrintMessage("the WB is Up to Date\n")
+ #
-
def Deactivated(self):
- # do something here if needed...
- Msg ("KiCadStepUpWB.Deactivated()\n")
+ # do something here if needed...
+ Msg("KiCadStepUpWB.Deactivated()\n")
+
@staticmethod
def ListDemos():
import os
+
import ksu_locator
dirs = []
# List all of the example files in an order that makes sense
module_base_path = ksu_locator.module_path()
- demo_dir_path = os.path.join(module_base_path, 'demo')
+ demo_dir_path = os.path.join(module_base_path, "demo")
dirs = os.listdir(demo_dir_path)
dirs.sort()
return dirs
+
##
+
###
dirs = KiCadStepUpWB.ListDemos()
-#print dirs
-#FreeCADGui.addCommand('ksuWBOpenDemo', ksuOpenDemo())
-#dirs = KiCadStepUpWB.ListDemos()
+# print dirs
+# FreeCADGui.addCommand('ksuWBOpenDemo', ksuOpenDemo())
+# dirs = KiCadStepUpWB.ListDemos()
for curFile in dirs:
FreeCADGui.addCommand(curFile, ksuExcDemo(curFile))
-#FreeCADGui.addPreferencePage(kSU_MainPrefPage,"kicadStepUpGui")
-#FreeCADGui.addPreferencePage(CalendarPage, "kicadStepUpGui")
-
+# FreeCADGui.addPreferencePage(kSU_MainPrefPage,"kicadStepUpGui")
+# FreeCADGui.addPreferencePage(CalendarPage, "kicadStepUpGui")
+
FreeCADGui.addWorkbench(KiCadStepUpWB)
diff --git a/SaveSettings.py b/SaveSettings.py
index 67e5988..96df247 100644
--- a/SaveSettings.py
+++ b/SaveSettings.py
@@ -1,36 +1,36 @@
-# -*- coding: utf-8 -*-
-#****************************************************************************
-#* *
-#* Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
-#* 3D exporter for FreeCAD *
-#* Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
-#* Copyright (c) 2015 *
-#* Maurice easyw@katamail.com *
-#* *
-#* Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
-#* *
-import FreeCAD, sys, os, re
-
+# ****************************************************************************
+# * *
+# * Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
+# * 3D exporter for FreeCAD *
+# * Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
+# * Copyright (c) 2015 *
+# * Maurice easyw@katamail.com *
+# * *
+# * Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
+# * *
+
+import FreeCAD
+
+
def reload_lib(lib):
- if (sys.version_info > (3, 0)):
- import importlib
- importlib.reload(lib)
- else:
- reload (lib)
+ import importlib
+
+ importlib.reload(lib)
def update_ksuGui():
- vrml_materials = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetBool('vrml_materials')
- mode_virtual = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetBool('mode_virtual')
- exp_step = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetBool('exp_step')
- #print('\'vrml_materials\' assigned to: ', vrml_materials)
-
+ vrml_materials = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetBool("vrml_materials")
+ mode_virtual = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetBool("mode_virtual")
+ exp_step = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetBool("exp_step")
+ # print('\'vrml_materials\' assigned to: ', vrml_materials)
+
import kicadStepUptools
- reload_lib( kicadStepUptools )
+
+ reload_lib(kicadStepUptools)
if not vrml_materials:
kicadStepUptools.KSUWidget.ui.cb_materials.setChecked(False) # Check by default True or False
else:
- kicadStepUptools.KSUWidget.ui.cb_materials.setChecked(True) # Check by default True or False
+ kicadStepUptools.KSUWidget.ui.cb_materials.setChecked(True) # Check by default True or False
if not mode_virtual:
kicadStepUptools.KSUWidget.ui.cb_virtual.setChecked(False) # Check by default True or False
else:
diff --git a/TranslateUtils.py b/TranslateUtils.py
index cf803c2..de4fc28 100644
--- a/TranslateUtils.py
+++ b/TranslateUtils.py
@@ -1,5 +1,3 @@
-# -*- coding: utf8 -*-
-
# ***************************************************************************
# * *
# * Copyright (c) 2017 Yorik van Havre *
@@ -36,4 +34,6 @@ def QT_TRANSLATE_NOOP(ctx, txt):
if hasattr(FreeCAD, "Qt"):
translate = FreeCAD.Qt.translate
else:
- from DraftTools import translate
+
+ def translate(_context, text):
+ return text
diff --git a/ZipStepImport.py b/ZipStepImport.py
index 2b1ea0d..71f8a88 100644
--- a/ZipStepImport.py
+++ b/ZipStepImport.py
@@ -1,44 +1,44 @@
-# -*- coding: utf-8 -*-
-#***************************************************************************
-#* *
-#* Copyright (c) 2018 Maurice *
-#* *
-#* This program is free software; you can redistribute it and/or modify *
-#* it under the terms of the GNU Lesser General Public License (LGPL) *
-#* as published by the Free Software Foundation; either version 2 of *
-#* the License, or (at your option) any later version. *
-#* for detail see the LICENCE text file. *
-#* *
-#* This program is distributed in the hope that it will be useful, *
-#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
-#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
-#* GNU Library General Public License for more details. *
-#* *
-#* You should have received a copy of the GNU Library General Public *
-#* License along with this program; if not, write to the Free Software *
-#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
-#* USA *
-#* *
-#***************************************************************************
+# ***************************************************************************
+# * *
+# * Copyright (c) 2018 Maurice *
+# * *
+# * This program is free software; you can redistribute it and/or modify *
+# * it under the terms of the GNU Lesser General Public License (LGPL) *
+# * as published by the Free Software Foundation; either version 2 of *
+# * the License, or (at your option) any later version. *
+# * for detail see the LICENCE text file. *
+# * *
+# * This program is distributed in the hope that it will be useful, *
+# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+# * GNU Library General Public License for more details. *
+# * *
+# * You should have received a copy of the GNU Library General Public *
+# * License along with this program; if not, write to the Free Software *
+# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+# * USA *
+# * *
+# ***************************************************************************
# from __future__ import print_function
-__title__ = "FreeCAD Zip STEP IGES importer"
+__title__ = "FreeCAD Zip STEP IGES importer"
__author__ = "Maurice"
-__url__ = "http://www.freecadweb.org"
+__url__ = "http://www.freecadweb.org"
-import os,zipfile,FreeCAD,tempfile,sys
+import os
+import tempfile
+import zipfile
-___ZipVersion___ = "1.0.5"
+import FreeCAD
+
+from TranslateUtils import translate
-try:
- import __builtin__ as builtin #py2
-except:
- import builtins as builtin #py3
+___ZipVersion___ = "1.0.5"
-if open.__module__ in ['__builtin__','io']:
- pyopen = open # because we'll redefine open below
+if open.__module__ in ["__builtin__", "io"]:
+ pyopen = open # because we'll redefine open below
def open(filename):
@@ -49,9 +49,9 @@ def open(filename):
FreeCAD.ActiveDocument = doc
read(filename)
return doc
-
-def insert(filename,docname):
+
+def insert(filename, docname):
"called when freecad wants to import a file"
try:
doc = FreeCAD.getDocument(docname)
@@ -65,101 +65,100 @@ def insert(filename,docname):
def decode(name):
"decodes encoded strings"
try:
- decodedName = (name.decode("utf8"))
+ decodedName = name.decode("utf8")
except UnicodeDecodeError:
try:
- decodedName = (name.decode("latin1"))
+ decodedName = name.decode("latin1")
except UnicodeDecodeError:
- FreeCAD.Console.PrintError(translate("Zip import","Error: Couldn't determine character encoding"))
+ FreeCAD.Console.PrintError(translate("Zip import", "Error: Couldn't determine character encoding"))
decodedName = name
return decodedName
def read(filename):
"reads the file and creates objects in the active document"
- #import importZip; reload(importZip)
- print("open Zip STEP version "+___ZipVersion___)
-
+ # import importZip; reload(importZip)
+ print("open Zip STEP version " + ___ZipVersion___)
+
z = zipfile.ZipFile(filename)
- l = z.printdir()
- #il = z.infolist()
+ z.printdir()
+ # il = z.infolist()
nl = z.namelist()
print("file list: ", nl)
- import ImportGui, FreeCADGui
-
+ import FreeCADGui
+ import ImportGui
+
for f in nl:
- if '.stp' in f.lower() or '.step' in f.lower(): #\
- #or '.igs' in f.lower() or '.iges' in f.lower():
- file_content = z.read(f)
- #sfe = z.extract(f)
- #print ('extracted ',sfe)
- print ('extracted ', f)
+ if ".stp" in f.lower() or ".step" in f.lower(): # \
+ # or '.igs' in f.lower() or '.iges' in f.lower():
+ z.read(f)
+ # sfe = z.extract(f)
+ # print ('extracted ',sfe)
+ print("extracted ", f)
# fname=os.path.splitext(os.path.basename(filename))[0]
# ext = os.path.splitext(os.path.basename(filename))[1]
- fname=f
- print('fname ',f)
- tempdir = tempfile.gettempdir() # get the current temporary directory
- tempfilepath = os.path.join(tempdir,fname) # + ext)
+ fname = f
+ print("fname ", f)
+ tempdir = tempfile.gettempdir() # get the current temporary directory
+ tempfilepath = os.path.join(tempdir, fname) # + ext)
z.extract(fname, tempdir)
- doc=FreeCAD.ActiveDocument
- ImportGui.insert(tempfilepath,doc.Name)
+ doc = FreeCAD.ActiveDocument
+ ImportGui.insert(tempfilepath, doc.Name)
FreeCADGui.SendMsgToActiveView("ViewFit")
try:
os.remove(tempfilepath)
except OSError:
- FreeCAD.Console.PrintError("error on removing "+tempfilepath+" file")
- pass
- elif '.fcstd' in f.lower(): #\
- fname=f
- tempdir = tempfile.gettempdir() # get the current temporary directory
- tempfilepath = os.path.join(tempdir,fname) # + ext)
+ FreeCAD.Console.PrintError("error on removing " + tempfilepath + " file")
+ elif ".fcstd" in f.lower(): # \
+ fname = f
+ tempdir = tempfile.gettempdir() # get the current temporary directory
+ tempfilepath = os.path.join(tempdir, fname) # + ext)
z.extract(fname, tempdir)
- doc=FreeCAD.ActiveDocument
- i=0
+ doc = FreeCAD.ActiveDocument
+ i = 0
for obj in FreeCAD.ActiveDocument.Objects:
- i+=1
- if i==0:
- FreeCAD.closeDocument(doc.Name)
+ i += 1
+ if i == 0:
+ FreeCAD.closeDocument(doc.Name)
FreeCAD.open(tempfilepath)
- #ImportGui.insert(tempfilepath,doc.Name)
+ # ImportGui.insert(tempfilepath,doc.Name)
FreeCADGui.SendMsgToActiveView("ViewFit")
try:
os.remove(tempfilepath)
except OSError:
- FreeCAD.Console.PrintError("error on removing "+tempfilepath+" file")
- pass
- elif '.brep' in f.lower(): #\
- fname=f
- tempdir = tempfile.gettempdir() # get the current temporary directory
- tempfilepath = os.path.join(tempdir,fname) # + ext)
+ FreeCAD.Console.PrintError("error on removing " + tempfilepath + " file")
+ elif ".brep" in f.lower(): # \
+ fname = f
+ tempdir = tempfile.gettempdir() # get the current temporary directory
+ tempfilepath = os.path.join(tempdir, fname) # + ext)
z.extract(fname, tempdir)
- doc=FreeCAD.ActiveDocument
+ doc = FreeCAD.ActiveDocument
import Part
- #Part.open(tempfilepath,doc.Name)
- Part.insert(tempfilepath,doc.Name)
- #FreeCAD.open(tempfilepath)
- #ImportGui.insert(tempfilepath,doc.Name)
+
+ # Part.open(tempfilepath,doc.Name)
+ Part.insert(tempfilepath, doc.Name)
+ # FreeCAD.open(tempfilepath)
+ # ImportGui.insert(tempfilepath,doc.Name)
FreeCADGui.SendMsgToActiveView("ViewFit")
try:
os.remove(tempfilepath)
except OSError:
- FreeCAD.Console.PrintError("error on removing "+tempfilepath+" file")
- pass
- elif '.kicad_mod' in f.lower() or '.kicad_pcb' in f.lower(): #\
- #or '.igs' in f.lower() or '.iges' in f.lower():
- file_content = z.read(f)
- print ('extracted ', f)
- fname=f
- print('fname ',f)
- tempdir = tempfile.gettempdir() # get the current temporary directory
- tempfilepath = os.path.join(tempdir,fname) # + ext)
+ FreeCAD.Console.PrintError("error on removing " + tempfilepath + " file")
+ elif ".kicad_mod" in f.lower() or ".kicad_pcb" in f.lower(): # \
+ # or '.igs' in f.lower() or '.iges' in f.lower():
+ z.read(f)
+ print("extracted ", f)
+ fname = f
+ print("fname ", f)
+ tempdir = tempfile.gettempdir() # get the current temporary directory
+ tempfilepath = os.path.join(tempdir, fname) # + ext)
z.extract(fname, tempdir)
- doc=FreeCAD.ActiveDocument
- import kicadStepUptools
- kicadStepUptools.open(tempfilepath,doc.Name)
+ doc = FreeCAD.ActiveDocument
+ import kicadStepUptools
+
+ kicadStepUptools.open(tempfilepath, doc.Name)
FreeCADGui.SendMsgToActiveView("ViewFit")
try:
os.remove(tempfilepath)
except OSError:
- FreeCAD.Console.PrintError("error on removing "+tempfilepath+" file")
- pass
\ No newline at end of file
+ FreeCAD.Console.PrintError("error on removing " + tempfilepath + " file")
diff --git a/_DXF_Import.py b/_DXF_Import.py
index 095e891..156b241 100644
--- a/_DXF_Import.py
+++ b/_DXF_Import.py
@@ -1,44 +1,42 @@
-# -*- coding: utf-8 -*-
-#***************************************************************************
-#* *
-#* Copyright (c) 2018 Maurice *
-#* *
-#* This program is free software; you can redistribute it and/or modify *
-#* it under the terms of the GNU Lesser General Public License (LGPL) *
-#* as published by the Free Software Foundation; either version 2 of *
-#* the License, or (at your option) any later version. *
-#* for detail see the LICENCE text file. *
-#* *
-#* This program is distributed in the hope that it will be useful, *
-#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
-#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
-#* GNU Library General Public License for more details. *
-#* *
-#* You should have received a copy of the GNU Library General Public *
-#* License along with this program; if not, write to the Free Software *
-#* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
-#* USA *
-#* *
-#***************************************************************************
+# ***************************************************************************
+# * *
+# * Copyright (c) 2018 Maurice *
+# * *
+# * This program is free software; you can redistribute it and/or modify *
+# * it under the terms of the GNU Lesser General Public License (LGPL) *
+# * as published by the Free Software Foundation; either version 2 of *
+# * the License, or (at your option) any later version. *
+# * for detail see the LICENCE text file. *
+# * *
+# * This program is distributed in the hope that it will be useful, *
+# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+# * GNU Library General Public License for more details. *
+# * *
+# * You should have received a copy of the GNU Library General Public *
+# * License along with this program; if not, write to the Free Software *
+# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
+# * USA *
+# * *
+# ***************************************************************************
# from __future__ import print_function
-__title__ = "FreeCAD Zip STEP IGES importer"
+__title__ = "FreeCAD Zip STEP IGES importer"
__author__ = "Maurice"
-__url__ = "http://www.freecadweb.org"
+__url__ = "http://www.freecadweb.org"
-import os,FreeCAD,tempfile,sys
+import os
-___DXFVersion___ = "1.4.0"
+import FreeCAD
+
+from TranslateUtils import translate
-try:
- import __builtin__ as builtin #py2
-except:
- import builtins as builtin #py3
+___DXFVersion___ = "1.4.0"
-if open.__module__ in ['__builtin__','io']:
- pyopen = open # because we'll redefine open below
+if open.__module__ in ["__builtin__", "io"]:
+ pyopen = open # because we'll redefine open below
def open(filename):
@@ -49,9 +47,9 @@ def open(filename):
FreeCAD.ActiveDocument = doc
read(filename)
return doc
-
-def insert(filename,docname):
+
+def insert(filename, docname):
"called when freecad wants to import a file"
try:
doc = FreeCAD.getDocument(docname)
@@ -65,27 +63,25 @@ def insert(filename,docname):
def decode(name):
"decodes encoded strings"
try:
- decodedName = (name.decode("utf8"))
+ decodedName = name.decode("utf8")
except UnicodeDecodeError:
try:
- decodedName = (name.decode("latin1"))
+ decodedName = name.decode("latin1")
except UnicodeDecodeError:
- FreeCAD.Console.PrintError(translate("Zip import","Error: Couldn't determine character encoding"))
+ FreeCAD.Console.PrintError(translate("Zip import", "Error: Couldn't determine character encoding"))
decodedName = name
return decodedName
def read(filename):
"reads the file and creates objects in the active document"
- print("open DXF version "+___DXFVersion___)
+ print("open DXF version " + ___DXFVersion___)
- import dxf_parser
from dxf_parser import _importDXF
+
global _dxfLibrary, _dxfColorMap, _dxfReader
- from dxf_parser import _dxfLibrary
- from dxf_parser import _dxfColorMap
- from dxf_parser import _dxfReader
- import ImportGui, FreeCADGui
-
- #_importDXF.processdxf(FreeCAD.ActiveDocument, filename, getShapes=True, reComputeFlag=True)
- _importDXF.open(filename)
\ No newline at end of file
+
+ from dxf_parser import _dxfColorMap, _dxfLibrary, _dxfReader
+
+ # _importDXF.processdxf(FreeCAD.ActiveDocument, filename, getShapes=True, reComputeFlag=True)
+ _importDXF.open(filename)
diff --git a/commits_num.py b/commits_num.py
index 7172356..02ef7a7 100644
--- a/commits_num.py
+++ b/commits_num.py
@@ -1,65 +1,69 @@
-import FreeCAD
import re
+import FreeCAD
+
# from https://gist.github.com/codsane/25f0fd100b565b3fce03d4bbd7e7bf33
+
def commitCount(u, r):
- # print('https://api.github.com/repos/{}/{}/commits?per_page=1'.format(u, r))
+ # print('https://api.github.com/repos/{}/{}/commits?per_page=1'.format(u, r))
try:
- #cuc
+ # cuc
import requests
- res = requests.get('https://api.github.com/repos/{}/{}/commits?per_page=1'.format(u, r))
+
+ res = requests.get(f"https://api.github.com/repos/{u}/{r}/commits?per_page=1")
# return res
- if hasattr(res, 'links'):
- return re.search(r'\d+$', res.links['last']['url']).group()
- return '0'
+ if hasattr(res, "links"):
+ return re.search(r"\d+$", res.links["last"]["url"]).group()
+ return "0"
except:
- import urllib
- print('using urllib')
- from urllib import request, error #URLError, HTTPError
- req = request.Request('https://api.github.com/repos/{}/{}/commits?per_page=1'.format(u, r))
+ print("using urllib")
+ from urllib import error, request # URLError, HTTPError
+
+ req = request.Request(f"https://api.github.com/repos/{u}/{r}/commits?per_page=1")
try:
response = request.urlopen(req)
- resp_ok = True
the_page = response.read().decode("utf-8")
- i=(the_page.find("message"))
- j=the_page[i+10:].find("\"")
- cmt_msg=the_page[i+10:i+10+j]
- #print(cmt_msg)
- #cmt_msg+="_cmtnum=634" NB all the commits must have commit message ending with _cmtnum=nnn
- k=cmt_msg.find("cmtnum=")
+ i = the_page.find("message")
+ j = the_page[i + 10 :].find('"')
+ cmt_msg = the_page[i + 10 : i + 10 + j]
+ # print(cmt_msg)
+ # cmt_msg+="_cmtnum=634" NB all the commits must have commit message ending with _cmtnum=nnn
+ k = cmt_msg.find("cmtnum=")
if k:
- return(cmt_msg[k+7:])
- else:
- return('0')
+ return cmt_msg[k + 7 :]
+ return "0"
# print (int(cmt_msg[k+8:]))
# print(the_page.find("message"))
# print(the_page[i+10:].find("\""))
# print(the_page[i+10:24])
# print(the_page[i+10:i+10+24])
-
+
except error.HTTPError as e:
- FreeCAD.Console.PrintWarning('The server couldn\'t fulfill the request.')
- FreeCAD.Console.PrintWarning('Error code: ' + str(e.code)+'\n')
- return '0'
+ FreeCAD.Console.PrintWarning("The server couldn't fulfill the request.")
+ FreeCAD.Console.PrintWarning("Error code: " + str(e.code) + "\n")
+ return "0"
except error.URLError as e:
- FreeCAD.Console.PrintWarning('We failed to reach a server.\n')
- FreeCAD.Console.PrintWarning('Reason: '+ str(e.reason)+'\n')
- return '0'
-#
+ FreeCAD.Console.PrintWarning("We failed to reach a server.\n")
+ FreeCAD.Console.PrintWarning("Reason: " + str(e.reason) + "\n")
+ return "0"
+
+
def latestCommitInfo(u, r):
- """ Get info about the latest commit of a GitHub repo """
- response = requests.get('https://api.github.com/repos/{}/{}/commits?per_page=1'.format(u, r))
- commit = response.json()[0]; commit['number'] = re.search(r'\d+$', response.links['last']['url']).group()
- return commit
+ """Get info about the latest commit of a GitHub repo"""
+ import requests
+
+ response = requests.get(f"https://api.github.com/repos/{u}/{r}/commits?per_page=1")
+ commit = response.json()[0]
+ commit["number"] = re.search(r"\d+$", response.links["last"]["url"]).group()
+ return commit
-
# u='easyw'
# r='kicadStepUpMod'
# print(int(commitCount(u, r)))
# # print(latestCommitInfo(u, r))
-#
+#
# u='easyw'
# r='Manipulator'
-# print(int(commitCount(u, r)))
\ No newline at end of file
+# print(int(commitCount(u, r)))
diff --git a/constrainator.py b/constrainator.py
index 7dba95d..9632da7 100644
--- a/constrainator.py
+++ b/constrainator.py
@@ -1,6 +1,5 @@
#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#****************************************************************************
+# ****************************************************************************
## todo :
# ok 1) add a dialog to set tolerance and constraint type
@@ -9,182 +8,199 @@
# ok 4) Line, Arcs, Bsplines, ArcOfEllipse are parsed
# 5) remove coindident bsplines (approx)
-import FreeCAD, Part, Sketcher
-from FreeCAD import Base
from math import sqrt
-__ksuConstrainator_version__='1.2.3'
+import FreeCAD
+import Part
+import Sketcher
+from FreeCAD import Base
+
+__ksuConstrainator_version__ = "1.2.3"
+
def sk_distance(p0, p1):
- return sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2)
-#
+ return sqrt((p0[0] - p1[0]) ** 2 + (p0[1] - p1[1]) ** 2)
+
def sanitizeSkBsp(s_name, dist_tolerance):
# s_name = 'Sketch001'
- s=FreeCAD.ActiveDocument.getObject(s_name)
- FreeCAD.Console.PrintWarning('check to sanitize\n')
- if 'Sketcher' in s.TypeId:
- FreeCAD.ActiveDocument.openTransaction('Sanitizing BSpline')
+ s = FreeCAD.ActiveDocument.getObject(s_name)
+ FreeCAD.Console.PrintWarning("check to sanitize\n")
+ if "Sketcher" in s.TypeId:
+ FreeCAD.ActiveDocument.openTransaction("Sanitizing BSpline")
idx_to_del = []
- geo_to_del = []
- inverted=False
+ inverted = False
# check for duplicates in splines
# NB!!! Knots are not reliable here to check!!!
- if 1: #len (s.Geometry) > 2: #cleaning algo approx valid for more than 2 splines
- for i,g in enumerate (s.Geometry):
- if 'BSplineCurve object' in str(g):
- j=i+1
- for bg in s.Geometry[(i + 1):]:
- if 'BSplineCurve object' in str(bg):
- if j not in idx_to_del:
- if (len(g.getPoles()) == len(bg.getPoles())):
- #print('equal pole nbrs')
- eqp = True
- if sk_distance(g.StartPoint,bg.StartPoint) > dist_tolerance:
- if sk_distance(g.StartPoint,bg.EndPoint) > dist_tolerance:
- eqp = False
- if sk_distance(g.EndPoint,bg.EndPoint) > dist_tolerance:
- if sk_distance(g.EndPoint,bg.StartPoint) > dist_tolerance:
- eqp = False
- if (eqp):
- if sk_distance(g.StartPoint,bg.StartPoint) > dist_tolerance:
- inverted=True
+ if 1: # len (s.Geometry) > 2: #cleaning algo approx valid for more than 2 splines
+ for i, g in enumerate(s.Geometry):
+ if "BSplineCurve object" in str(g):
+ j = i + 1
+ for bg in s.Geometry[(i + 1) :]:
+ if "BSplineCurve object" in str(bg) and j not in idx_to_del:
+ if len(g.getPoles()) == len(bg.getPoles()):
+ # print('equal pole nbrs')
+ eqp = True
+ if sk_distance(g.StartPoint, bg.StartPoint) > dist_tolerance:
+ if sk_distance(g.StartPoint, bg.EndPoint) > dist_tolerance:
+ eqp = False
+ if sk_distance(g.EndPoint, bg.EndPoint) > dist_tolerance:
+ if sk_distance(g.EndPoint, bg.StartPoint) > dist_tolerance:
+ eqp = False
+ if eqp:
+ if sk_distance(g.StartPoint, bg.StartPoint) > dist_tolerance:
+ inverted = True
+ else:
+ inverted = False
+ print("identical splines, inverted=", inverted)
+ # print(g.getPoles())
+ # print(bg.getPoles())
+ if j not in idx_to_del:
+ print("len ", len(bg.getPoles()))
+ if not inverted:
+ for k, kn in enumerate(bg.getPoles()):
+ # a = float(kn); b = float(g.KnotSequence[k])
+ # print(k)
+ a = kn
+ b = g.getPole(k + 1)
+ # print(kn,g.getPole(k+1))
+ # print('dif ',(float(kn)-float(g.KnotSequence[k])))
+ # print('abs ',abs(float(kn)-float(g.KnotSequence[k])))
+ # print(a,b)
+ # print(a[0],a[1],a[2])
+ # print(b[0],b[1],b[2])
+ # print('dif ',abs(a[0]-b[0]),abs(a[1]-b[1]),abs(a[2]-b[2]))
+ # print('abs ',abs(a-b))
+ # if abs(float(kn)-float(g.KnotSequence[k])) > dist_tolerance:
+ if (
+ abs(a[0] - b[0]) > dist_tolerance
+ or abs(a[1] - b[1]) > dist_tolerance
+ or abs(a[2] - b[2]) > dist_tolerance
+ ):
+ print("node NOT coincident")
+ # print(a,b)
+ eqp = False
+ break # break the for loop
+ # print('next--')
else:
- inverted=False
- print ('identical splines, inverted=',inverted )
- #print(g.getPoles())
- #print(bg.getPoles())
- if j not in idx_to_del:
- print ('len ',len(bg.getPoles()))
- if inverted == False:
- for k,kn in enumerate (bg.getPoles()):
- #a = float(kn); b = float(g.KnotSequence[k])
- #print(k)
- a = kn; b = g.getPole(k+1)
- #print(kn,g.getPole(k+1))
- #print('dif ',(float(kn)-float(g.KnotSequence[k])))
- #print('abs ',abs(float(kn)-float(g.KnotSequence[k])))
- #print(a,b)
- #print(a[0],a[1],a[2])
- #print(b[0],b[1],b[2])
- #print('dif ',abs(a[0]-b[0]),abs(a[1]-b[1]),abs(a[2]-b[2]))
- #print('abs ',abs(a-b))
- #if abs(float(kn)-float(g.KnotSequence[k])) > dist_tolerance:
- if abs(a[0]-b[0]) > dist_tolerance or abs(a[1]-b[1]) > dist_tolerance or abs(a[2]-b[2]) > dist_tolerance:
- print('node NOT coincident')
- #print(a,b)
- eqp=False
- break # break the for loop
- #print('next--')
- else:
- l = len(bg.getPoles())
- for k,kn in enumerate (bg.getPoles()):
- #a = float(kn); b = float(g.KnotSequence[k])
- #print(k)
- a = kn; b = g.getPole(l-k)
- #print(kn,g.getPole(l-k))
- #print('dif ',(float(kn)-float(g.KnotSequence[k])))
- #print('abs ',abs(float(kn)-float(g.KnotSequence[k])))
- #print(a,b)
- #print(a[0],a[1],a[2])
- #print(b[0],b[1],b[2])
- #print('dif ',abs(a[0]-b[0]),abs(a[1]-b[1]),abs(a[2]-b[2]))
- #print('abs ',abs(a-b))
- #if abs(float(kn)-float(g.KnotSequence[k])) > dist_tolerance:
- if abs(a[0]-b[0]) > dist_tolerance or abs(a[1]-b[1]) > dist_tolerance or abs(a[2]-b[2]) > dist_tolerance:
- print('node NOT coincident')
- #print(a,b)
- eqp=False
- break # break the for loop
- #print('next--')
- if (eqp):
- idx_to_del.append(j)
- j+=1
- j=0
- #print(idx_to_del)
- if len(idx_to_del) >0:
- FreeCAD.Console.PrintMessage(u'sanitizing '+s.Label)
- FreeCAD.Console.PrintMessage('\n')
- idx_to_del.sort()
- #print(idx_to_del)
- idx_to_del.reverse()
- #print(idx_to_del)
- #stop
+ l = len(bg.getPoles())
+ for k, kn in enumerate(bg.getPoles()):
+ # a = float(kn); b = float(g.KnotSequence[k])
+ # print(k)
+ a = kn
+ b = g.getPole(l - k)
+ # print(kn,g.getPole(l-k))
+ # print('dif ',(float(kn)-float(g.KnotSequence[k])))
+ # print('abs ',abs(float(kn)-float(g.KnotSequence[k])))
+ # print(a,b)
+ # print(a[0],a[1],a[2])
+ # print(b[0],b[1],b[2])
+ # print('dif ',abs(a[0]-b[0]),abs(a[1]-b[1]),abs(a[2]-b[2]))
+ # print('abs ',abs(a-b))
+ # if abs(float(kn)-float(g.KnotSequence[k])) > dist_tolerance:
+ if (
+ abs(a[0] - b[0]) > dist_tolerance
+ or abs(a[1] - b[1]) > dist_tolerance
+ or abs(a[2] - b[2]) > dist_tolerance
+ ):
+ print("node NOT coincident")
+ # print(a,b)
+ eqp = False
+ break # break the for loop
+ # print('next--')
+ if eqp:
+ idx_to_del.append(j)
+ j += 1
+ j = 0
+ # print(idx_to_del)
+ if len(idx_to_del) > 0:
+ FreeCAD.Console.PrintMessage("sanitizing " + s.Label)
+ FreeCAD.Console.PrintMessage("\n")
+ idx_to_del.sort()
+ # print(idx_to_del)
+ idx_to_del.reverse()
+ # print(idx_to_del)
+ # stop
for i, e in enumerate(idx_to_del):
- #print('to delete ',s.Geometry[(e)],e)
- print('deleting identical geo')
- #print(s.Geometry)
+ # print('to delete ',s.Geometry[(e)],e)
+ print("deleting identical geo")
+ # print(s.Geometry)
s.delGeometry(e)
- #print(s.Geometry)
+ # print(s.Geometry)
FreeCAD.ActiveDocument.commitTransaction()
return s.Geometry
- else:
- return None
+ return None
+
+
##
def sanitizeSk(s_name, edg_tol):
- ''' simplifying & sanitizing sketches '''
-
- s=FreeCAD.ActiveDocument.getObject(s_name)
- FreeCAD.Console.PrintWarning('check to sanitize\n')
+ """simplifying & sanitizing sketches"""
+
+ s = FreeCAD.ActiveDocument.getObject(s_name)
+ FreeCAD.Console.PrintWarning("check to sanitize\n")
# print(s.TypeId)
- if 'Sketcher' in s.TypeId:
- idx_to_del=[]
- #print(s.Geometry)
- for i,g in enumerate (s.Geometry):
- #print(g,i)
+ if "Sketcher" in s.TypeId:
+ idx_to_del = []
+ # print(s.Geometry)
+ for i, g in enumerate(s.Geometry):
+ # print(g,i)
# g.length()
- #print('str(g)',str(g))
- if 'Line' in str(g):
- #print(g.length())
+ # print('str(g)',str(g))
+ if "Line" in str(g):
+ # print(g.length())
lng = sk_distance(g.StartPoint, g.EndPoint)
- #print(lng)
+ # print(lng)
if lng <= edg_tol:
- print(g,i)
- FreeCAD.Console.PrintWarning('too short\n')
- idx_to_del.append(i)
- if 'Circle' in str(g):
- if g.Radius <= edg_tol:
- print(g,i)
- FreeCAD.Console.PrintWarning('too short\n')
+ print(g, i)
+ FreeCAD.Console.PrintWarning("too short\n")
idx_to_del.append(i)
- if 'Arc' in str(g):
- #print('str(g)',str(g))
- #stop
+ if "Circle" in str(g) and g.Radius <= edg_tol:
+ print(g, i)
+ FreeCAD.Console.PrintWarning("too short\n")
+ idx_to_del.append(i)
+ if "Arc" in str(g):
+ # print('str(g)',str(g))
+ # stop
lng = sk_distance(g.StartPoint, g.EndPoint)
- #print(lng)
+ # print(lng)
if lng <= edg_tol:
- print(g,i)
- FreeCAD.Console.PrintWarning('too short\n')
+ print(g, i)
+ FreeCAD.Console.PrintWarning("too short\n")
idx_to_del.append(i)
- j=0
- if len(idx_to_del) >0:
- FreeCAD.Console.PrintWarning(u'sanitizing '+s.Label+'\n')
+ j = 0
+ if len(idx_to_del) > 0:
+ FreeCAD.Console.PrintWarning("sanitizing " + s.Label + "\n")
for i in idx_to_del:
- s.delGeometry(i-j)
- j+=1
+ s.delGeometry(i - j)
+ j += 1
else:
- FreeCAD.Console.PrintMessage('nothing to sanitize\n')
+ FreeCAD.Console.PrintMessage("nothing to sanitize\n")
+
+
##
+
def add_constraints(s_name, edge_tolerance, add_Constraints):
- """ adding coincident points constraints """
-
- s=FreeCAD.ActiveDocument.getObject(s_name)
-
- FreeCAD.Console.PrintMessage('Constrainator version '+__ksuConstrainator_version__+'\n')
- FreeCAD.Console.PrintMessage('adding '+add_Constraints+' constraints with '+str(edge_tolerance)+'mm tolerance\n' )
- if hasattr(Part,"LineSegment"):
+ """adding coincident points constraints"""
+
+ s = FreeCAD.ActiveDocument.getObject(s_name)
+
+ FreeCAD.Console.PrintMessage("Constrainator version " + __ksuConstrainator_version__ + "\n")
+ FreeCAD.Console.PrintMessage(
+ "adding " + add_Constraints + " constraints with " + str(edge_tolerance) + "mm tolerance\n",
+ )
+ if hasattr(Part, "LineSegment"):
g_geom_points = {
Base.Vector: [1],
Part.LineSegment: [1, 2], # first point, last point
Part.Circle: [0, 3], # curve, center
Part.ArcOfCircle: [1, 2, 3], # first point, last point, center
- Part.BSplineCurve: [0,1,2,3], # for poles
- Part.ArcOfEllipse: [0,1,2,3], #
- Part.Ellipse: [0,1], #
- Part.ArcOfHyperbola: [0,1,2], #
- Part.ArcOfParabola: [0,1,2], #
- Part.Point: [0], #
+ Part.BSplineCurve: [0, 1, 2, 3], # for poles
+ Part.ArcOfEllipse: [0, 1, 2, 3],
+ Part.Ellipse: [0, 1],
+ Part.ArcOfHyperbola: [0, 1, 2],
+ Part.ArcOfParabola: [0, 1, 2],
+ Part.Point: [0],
}
else:
g_geom_points = {
@@ -192,128 +208,126 @@ def add_constraints(s_name, edge_tolerance, add_Constraints):
Part.Line: [1, 2], # first point, last point
Part.Circle: [0, 3], # curve, center
Part.ArcOfCircle: [1, 2, 3], # first point, last point, center
- Part.BSplineCurve: [0,1,2,3], # for poles
- Part.ArcOfEllipse: [0,1,2,3], #
- Part.Point: [0], #
+ Part.BSplineCurve: [0, 1, 2, 3], # for poles
+ Part.ArcOfEllipse: [0, 1, 2, 3],
+ Part.Point: [0],
}
- points=[]
- geoms=[]
- #print len((s.Geometry))
- #stop
- for geom_index in range(len((s.Geometry))):
- if hasattr(s,'GeometryFacadeList'):
+ geoms = []
+ # print len((s.Geometry))
+ # stop
+ for geom_index in range(len(s.Geometry)):
+ if hasattr(s, "GeometryFacadeList"):
# Gm = s.GeometryFacadeList.Geometry
Gc = s.GeometryFacadeList
else:
# Gm = s.Geometry
Gc = s.Geometry
- #if not(s.Geometry[geom_index].Construction):
- if not(Gc[geom_index].Construction):
+ # if not(s.Geometry[geom_index].Construction):
+ if not (Gc[geom_index].Construction):
point_indexes = g_geom_points[type(s.Geometry[geom_index])]
- #sayerr(point_indexes), say (geom_index)
- #if 'Line' in type(PCB_Sketch.Geometry[geom_index]).__name__:
-
- if 'ArcOfCircle' in type(s.Geometry[geom_index]).__name__\
- or 'Line' in type(s.Geometry[geom_index]).__name__:
+ # sayerr(point_indexes), say (geom_index)
+ # if 'Line' in type(PCB_Sketch.Geometry[geom_index]).__name__:
+
+ if (
+ "ArcOfCircle" in type(s.Geometry[geom_index]).__name__
+ or "Line" in type(s.Geometry[geom_index]).__name__
+ ):
point1 = s.getPoint(geom_index, point_indexes[0])
- #sayerr(str(point1[0])+';'+str(point1[1]))
+ # sayerr(str(point1[0])+';'+str(point1[1]))
point2 = s.getPoint(geom_index, point_indexes[1])
- #sayw(str(point2[0])+';'+str(point1[1]))
- #points.append([[point1[0],point1[1]],[geom_index],[1]])
- #points.append([[point2[0],point2[1]],[geom_index],[2]])
- #points.append([[point1[0],point1[1]],[geom_index]]) #,[1]])
- #points.append([[point2[0],point2[1]],[geom_index]]) #,[2]])
- if 'Line' in type(s.Geometry[geom_index]).__name__:
- tp = 'Line'
- else:
- tp = 'Arc'
- geoms.append([point1[0],point1[1],point2[0],point2[1],tp])
- elif 'ArcOfEllipse' in type(s.Geometry[geom_index]).__name__\
- or 'ArcOfHyperbola' in type(s.Geometry[geom_index]).__name__\
- or 'ArcOfParabola' in type(s.Geometry[geom_index]).__name__:
+ # sayw(str(point2[0])+';'+str(point1[1]))
+ # points.append([[point1[0],point1[1]],[geom_index],[1]])
+ # points.append([[point2[0],point2[1]],[geom_index],[2]])
+ # points.append([[point1[0],point1[1]],[geom_index]]) #,[1]])
+ # points.append([[point2[0],point2[1]],[geom_index]]) #,[2]])
+ tp = "Line" if "Line" in type(s.Geometry[geom_index]).__name__ else "Arc"
+ geoms.append([point1[0], point1[1], point2[0], point2[1], tp])
+ elif (
+ "ArcOfEllipse" in type(s.Geometry[geom_index]).__name__
+ or "ArcOfHyperbola" in type(s.Geometry[geom_index]).__name__
+ or "ArcOfParabola" in type(s.Geometry[geom_index]).__name__
+ ):
point1 = s.getPoint(geom_index, point_indexes[1])
point2 = s.getPoint(geom_index, point_indexes[2])
- tp = 'Arc'
- geoms.append([point1[0],point1[1],point2[0],point2[1],tp])
- elif 'Ellipse' in type(s.Geometry[geom_index]).__name__:
- pass
- elif 'Point' in type(s.Geometry[geom_index]).__name__:
+ tp = "Arc"
+ geoms.append([point1[0], point1[1], point2[0], point2[1], tp])
+ elif "Ellipse" in type(s.Geometry[geom_index]).__name__ or "Point" in type(s.Geometry[geom_index]).__name__:
pass
#
- #print geom
+ # print geom
sk_constraints = []
- cnt=1
+ cnt = 1
# print addConstraints, ' constraints'
# stop
- if add_Constraints=='all':
- if hasattr (FreeCAD.ActiveDocument.getObject(s_name), "autoconstraint"):
- FreeCAD.Console.PrintWarning('using constrainator -> coincident\n')
+ if add_Constraints == "all":
+ if hasattr(FreeCAD.ActiveDocument.getObject(s_name), "autoconstraint"):
+ FreeCAD.Console.PrintWarning("using constrainator -> coincident\n")
sanitizeSk(s_name, edge_tolerance)
- sk1=FreeCAD.ActiveDocument.getObject(s_name)
+ sk1 = FreeCAD.ActiveDocument.getObject(s_name)
sk1.detectMissingPointOnPointConstraints(edge_tolerance)
sk1.makeMissingPointOnPointCoincident()
FreeCAD.activeDocument().recompute()
sk1.autoRemoveRedundants(True)
sk1.solve()
FreeCAD.activeDocument().recompute()
- FreeCAD.Console.PrintWarning('using constrainator -> H&V\n')
+ FreeCAD.Console.PrintWarning("using constrainator -> H&V\n")
for i, geo in enumerate(geoms):
- #for i in range(len(geom)):
- p_g0_0=[geo[0],geo[1]]
- p_g0_1=[geo[2],geo[3]]
- #print p_g0_0,pg_g0_1
- #sayw(abs(p_g0_0[0]-p_g0_1[0]))
- if abs(p_g0_0[0]-p_g0_1[0])< edge_tolerance and geo[4] == 'Line':
- #s.addConstraint(Sketcher.Constraint('Vertical',i))
- sk_constraints.append(Sketcher.Constraint('Vertical',i))
- elif abs(p_g0_0[1]-p_g0_1[1])< edge_tolerance and geo[4] == 'Line':
- #s.addConstraint(Sketcher.Constraint('Horizontal',i))
- sk_constraints.append(Sketcher.Constraint('Horizontal',i))
- j=i+1
+ # for i in range(len(geom)):
+ p_g0_0 = [geo[0], geo[1]]
+ p_g0_1 = [geo[2], geo[3]]
+ # print p_g0_0,pg_g0_1
+ # sayw(abs(p_g0_0[0]-p_g0_1[0]))
+ if abs(p_g0_0[0] - p_g0_1[0]) < edge_tolerance and geo[4] == "Line":
+ # s.addConstraint(Sketcher.Constraint('Vertical',i))
+ sk_constraints.append(Sketcher.Constraint("Vertical", i))
+ elif abs(p_g0_0[1] - p_g0_1[1]) < edge_tolerance and geo[4] == "Line":
+ # s.addConstraint(Sketcher.Constraint('Horizontal',i))
+ sk_constraints.append(Sketcher.Constraint("Horizontal", i))
+ j = i + 1
else:
for i, geo in enumerate(geoms):
- #for i in range(len(geom)):
- p_g0_0=[geo[0],geo[1]]
- p_g0_1=[geo[2],geo[3]]
- #print p_g0_0,pg_g0_1
- #sayw(abs(p_g0_0[0]-p_g0_1[0]))
- if abs(p_g0_0[0]-p_g0_1[0])< edge_tolerance and geo[4] == 'Line':
- #s.addConstraint(Sketcher.Constraint('Vertical',i))
- sk_constraints.append(Sketcher.Constraint('Vertical',i))
- elif abs(p_g0_0[1]-p_g0_1[1])< edge_tolerance and geo[4] == 'Line':
- #s.addConstraint(Sketcher.Constraint('Horizontal',i))
- sk_constraints.append(Sketcher.Constraint('Horizontal',i))
- j=i+1
- FreeCAD.Console.PrintWarning('using old constrainator\n')
- for geo2 in geoms[(i + 1):]:
- p_g1_0=[geo2[0],geo2[1]]
- p_g1_1=[geo2[2],geo2[3]]
- #rint p_g0_0, p_g0_1
- #rint p_g1_0, p_g1_1
- if sk_distance(p_g0_0,p_g1_0)< edge_tolerance:
- ##App.ActiveDocument.PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',0,2,3,1))
- #s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,1))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,1,j,1))
- #print i,1,i+1,1
- elif sk_distance(p_g0_0,p_g1_1)< edge_tolerance:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,2))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,1,j,2))
- #print i,1,i+1,2
- elif sk_distance(p_g0_1,p_g1_0)< edge_tolerance:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,1))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,2,j,1))
- #print i,2,i+1,1
- elif sk_distance(p_g0_1,p_g1_1)< edge_tolerance:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,2))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,2,j,2))
- #print i,2,i+1,2
- j=j+1
- cnt=cnt+1
- elif add_Constraints=='coincident':
- if hasattr (FreeCAD.ActiveDocument.getObject(s_name), "autoconstraint"):
- FreeCAD.Console.PrintWarning('using constrainator\n')
+ # for i in range(len(geom)):
+ p_g0_0 = [geo[0], geo[1]]
+ p_g0_1 = [geo[2], geo[3]]
+ # print p_g0_0,pg_g0_1
+ # sayw(abs(p_g0_0[0]-p_g0_1[0]))
+ if abs(p_g0_0[0] - p_g0_1[0]) < edge_tolerance and geo[4] == "Line":
+ # s.addConstraint(Sketcher.Constraint('Vertical',i))
+ sk_constraints.append(Sketcher.Constraint("Vertical", i))
+ elif abs(p_g0_0[1] - p_g0_1[1]) < edge_tolerance and geo[4] == "Line":
+ # s.addConstraint(Sketcher.Constraint('Horizontal',i))
+ sk_constraints.append(Sketcher.Constraint("Horizontal", i))
+ j = i + 1
+ FreeCAD.Console.PrintWarning("using old constrainator\n")
+ for geo2 in geoms[(i + 1) :]:
+ p_g1_0 = [geo2[0], geo2[1]]
+ p_g1_1 = [geo2[2], geo2[3]]
+ # rint p_g0_0, p_g0_1
+ # rint p_g1_0, p_g1_1
+ if sk_distance(p_g0_0, p_g1_0) < edge_tolerance:
+ ##App.ActiveDocument.PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',0,2,3,1))
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,1))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 1, j, 1))
+ # print i,1,i+1,1
+ elif sk_distance(p_g0_0, p_g1_1) < edge_tolerance:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,2))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 1, j, 2))
+ # print i,1,i+1,2
+ elif sk_distance(p_g0_1, p_g1_0) < edge_tolerance:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,1))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 2, j, 1))
+ # print i,2,i+1,1
+ elif sk_distance(p_g0_1, p_g1_1) < edge_tolerance:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,2))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 2, j, 2))
+ # print i,2,i+1,2
+ j = j + 1
+ cnt = cnt + 1
+ elif add_Constraints == "coincident":
+ if hasattr(FreeCAD.ActiveDocument.getObject(s_name), "autoconstraint"):
+ FreeCAD.Console.PrintWarning("using constrainator\n")
sanitizeSk(s_name, edge_tolerance)
- sk1=FreeCAD.ActiveDocument.getObject(s_name)
+ sk1 = FreeCAD.ActiveDocument.getObject(s_name)
sk1.detectMissingPointOnPointConstraints(edge_tolerance)
sk1.makeMissingPointOnPointCoincident()
FreeCAD.activeDocument().recompute()
@@ -321,68 +335,68 @@ def add_constraints(s_name, edge_tolerance, add_Constraints):
sk1.solve()
FreeCAD.activeDocument().recompute()
else:
- FreeCAD.Console.PrintWarning('using old constrainator\n')
+ FreeCAD.Console.PrintWarning("using old constrainator\n")
for i, geo in enumerate(geoms):
- #for i in range(len(geom)):
- p_g0_0=[geo[0],geo[1]]
- p_g0_1=[geo[2],geo[3]]
- #print p_g0_0,pg_g0_1
- #if add_Constraints=='all':
+ # for i in range(len(geom)):
+ p_g0_0 = [geo[0], geo[1]]
+ p_g0_1 = [geo[2], geo[3]]
+ # print p_g0_0,pg_g0_1
+ # if add_Constraints=='all':
# if abs(p_g0_0[0]-p_g0_1[0])< edge_tolerance:
# s.addConstraint(Sketcher.Constraint('Vertical',i))
# elif abs(p_g0_0[1]-p_g0_1[1])< edge_tolerance:
# s.addConstraint(Sketcher.Constraint('Horizontal',i))
- j=i+1
- for geo2 in geoms[(i + 1):]:
- p_g1_0=[geo2[0],geo2[1]]
- p_g1_1=[geo2[2],geo2[3]]
- #rint p_g0_0, p_g0_1
- #rint p_g1_0, p_g1_1
- if sk_distance(p_g0_0,p_g1_0)< edge_tolerance:
- ##App.ActiveDocument.PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',0,2,3,1))
- #s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,1))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,1,j,1))
- #print i,1,i+1,1
- elif sk_distance(p_g0_0,p_g1_1)< edge_tolerance:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,2))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,1,j,2))
- #print i,1,i+1,2
- elif sk_distance(p_g0_1,p_g1_0)< edge_tolerance:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,1))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,2,j,1))
- #print i,2,i+1,1
- elif sk_distance(p_g0_1,p_g1_1)< edge_tolerance:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,2))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,2,j,2))
- #print i,2,i+1,2
- j=j+1
- cnt=cnt+1
+ j = i + 1
+ for geo2 in geoms[(i + 1) :]:
+ p_g1_0 = [geo2[0], geo2[1]]
+ p_g1_1 = [geo2[2], geo2[3]]
+ # rint p_g0_0, p_g0_1
+ # rint p_g1_0, p_g1_1
+ if sk_distance(p_g0_0, p_g1_0) < edge_tolerance:
+ ##App.ActiveDocument.PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',0,2,3,1))
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,1))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 1, j, 1))
+ # print i,1,i+1,1
+ elif sk_distance(p_g0_0, p_g1_1) < edge_tolerance:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,2))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 1, j, 2))
+ # print i,1,i+1,2
+ elif sk_distance(p_g0_1, p_g1_0) < edge_tolerance:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,1))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 2, j, 1))
+ # print i,2,i+1,1
+ elif sk_distance(p_g0_1, p_g1_1) < edge_tolerance:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,2))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 2, j, 2))
+ # print i,2,i+1,2
+ j = j + 1
+ cnt = cnt + 1
if len(sk_constraints) > 0:
old_sk_constraints = []
for c in s.Constraints:
- #sayw(c)
- #if add_Constraints=='coincident':
+ # sayw(c)
+ # if add_Constraints=='coincident':
# say('c')
- if (add_Constraints == "coincident"):
- if ("Coincident" not in str(c)):
+ if add_Constraints == "coincident":
+ if "Coincident" not in str(c):
old_sk_constraints.append(c)
- #say('appending '+str(c))
- elif (add_Constraints=='all'):
- if hasattr (FreeCAD.ActiveDocument.getObject(s_name), "autoconstraint"):
- if ('Vertical' not in str(c)) and ('Horizontal' not in str(c)):
+ # say('appending '+str(c))
+ elif add_Constraints == "all":
+ if hasattr(FreeCAD.ActiveDocument.getObject(s_name), "autoconstraint"):
+ if ("Vertical" not in str(c)) and ("Horizontal" not in str(c)):
old_sk_constraints.append(c)
- elif ('Coincident' not in str(c)) and ('Vertical' not in str(c)) and ('Horizontal' not in str(c)):
+ elif ("Coincident" not in str(c)) and ("Vertical" not in str(c)) and ("Horizontal" not in str(c)):
old_sk_constraints.append(c)
- #say('appending all '+str(c))
+ # say('appending all '+str(c))
s.Constraints = []
- #sayw(old_sk_constraints)
- for oc in old_sk_constraints:
- sk_constraints.append(oc)
- #say(sk_constraints)
+ # sayw(old_sk_constraints)
+ sk_constraints.extend(old_sk_constraints)
+ # say(sk_constraints)
s.addConstraint(sk_constraints)
FreeCAD.ActiveDocument.recompute()
- #print 'counter ',cnt
- #print geo2
-
+ # print 'counter ',cnt
+ # print geo2
+
+
###
diff --git a/exchangePositions.py b/exchangePositions.py
index 556096e..f908af0 100644
--- a/exchangePositions.py
+++ b/exchangePositions.py
@@ -1,731 +1,853 @@
-# -*- coding: utf-8 -*-
-#
-
## https://www.freecadweb.org/wiki/Placement
-# App.ActiveDocument.Cylinder.Placement=App.Placement(App.Vector(0,0,0), App.Rotation(10,20,30), App.Vector(0,0,0))
-# App.Rotation(10,20,30) = Euler Angle
+# App.ActiveDocument.Cylinder.Placement=App.Placement(App.Vector(0,0,0), App.Rotation(10,20,30), App.Vector(0,0,0))
+# App.Rotation(10,20,30) = Euler Angle
## https://forum.freecadweb.org/viewtopic.php?t=11799
__version_exchPos__ = "1.2.3"
-import FreeCAD, FreeCADGui,sys, os
-from FreeCAD import Base
+import os
+
+import FreeCAD
+import FreeCADGui
import Part
+import PySide
+from FreeCAD import Base
+from PySide import QtCore, QtGui
-import PySide
-from PySide import QtGui, QtCore
QtWidgets = QtGui
-#from PySide.QtGui import QTreeWidgetItemIterator
+# from PySide.QtGui import QTreeWidgetItemIterator
+import datetime
+import difflib
+import re
+from os.path import expanduser
+
import ksu_locator
-from os.path import expanduser
-import difflib, re, time, datetime
+FreeCAD.Console.PrintWarning("MCAD export/check version =" + str(__version_exchPos__) + "\n")
-FreeCAD.Console.PrintWarning('MCAD export/check version ='+ str(__version_exchPos__)+'\n')
+generateSketch = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetBool("generate_sketch")
-generateSketch = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetBool('generate_sketch')
+generate_sketch = True
-generate_sketch=True
-def PLine(prm1,prm2):
- if hasattr(Part,"LineSegment"):
+def PLine(prm1, prm2):
+ if hasattr(Part, "LineSegment"):
return Part.LineSegment(prm1, prm2)
- else:
- return Part.Line(prm1, prm2)
-
-def get_Selected ():
- InListRec=[]
- InListRecSelEx=FreeCADGui.Selection.getSelectionEx('',False)[0]
- InListRecSubEN=InListRecSelEx.SubElementNames
- print (InListRecSubEN)
- if len (InListRecSubEN) >=1:
+ return Part.Line(prm1, prm2)
+
+
+def get_Selected():
+ InListRec = []
+ InListRecSelEx = FreeCADGui.Selection.getSelectionEx("", False)[0]
+ InListRecSubEN = InListRecSelEx.SubElementNames
+ print(InListRecSubEN)
+ if len(InListRecSubEN) >= 1:
InListRec.append(InListRecSelEx.Object.Name)
- InListRec.extend(InListRecSubEN[0].split('.'))
- print (InListRec)
- if len(InListRec)>1:
- ro = InListRec.pop()
+ InListRec.extend(InListRecSubEN[0].split("."))
+ print(InListRec)
+ if len(InListRec) > 1:
+ InListRec.pop()
for oName in InListRec:
- print ('hierarchy \"'+FreeCAD.ActiveDocument.getObject(oName).Label+'\"')
- #print (InListRec[:-1])
- print (InListRec)
- print ('top Level Obj \"'+InListRecSelEx.Object.Label+'\"')
+ print('hierarchy "' + FreeCAD.ActiveDocument.getObject(oName).Label + '"')
+ # print (InListRec[:-1])
+ print(InListRec)
+ print('top Level Obj "' + InListRecSelEx.Object.Label + '"')
if len(InListRec) > 0:
- print ('Selected Obj \"'+FreeCAD.ActiveDocument.getObject(InListRec[-1]).Label+'\"')
+ print('Selected Obj "' + FreeCAD.ActiveDocument.getObject(InListRec[-1]).Label + '"')
else:
- print ('Selected Obj \"'+InListRecSelEx.Object.Label+'\"')
- print (InListRec)
- #print (len(InListRecSubEN));print (len(InListRec))
-
-def get_sorted_list (obj):
- lvl=10000
- completed=0
- listUs=obj.InListRecursive
- #sayerr('unsorted')
- #for p in listUs:
+ print('Selected Obj "' + InListRecSelEx.Object.Label + '"')
+ print(InListRec)
+ # print (len(InListRecSubEN));print (len(InListRec))
+
+
+def get_sorted_list(obj):
+ lvl = 10000
+ # sayerr('unsorted')
+ # for p in listUs:
# print p.Label
- listUsName=[]
+ listUsName = []
for o in obj.InListRecursive:
listUsName.append(o.Name)
- listS=[]
- i=0
- #print(listUsName)
- i=0
- while len (listUsName) > 0:
+ listS = []
+ # print(listUsName)
+ while len(listUsName) > 0:
for apName in listUsName:
- #apName=listUsName[i]
- ap=FreeCAD.ActiveDocument.getObject(apName)
+ # apName=listUsName[i]
+ ap = FreeCAD.ActiveDocument.getObject(apName)
if len(ap.InListRecursive) < lvl:
lvl = len(ap.InListRecursive)
top = ap
topName = ap.Name
listS.append(top)
- #print topName
- idx=listUsName.index(topName)
- #sayw(idx)
+ # print topName
+ idx = listUsName.index(topName)
+ # sayw(idx)
listUsName.pop(idx)
- lvl=10000
- #sayerr(listUsName)
-
+ lvl = 10000
+ # sayerr(listUsName)
+
return listS
+
+
##
def gui_addSelection(obj):
- if hasattr(obj,'InListExRecursive'): #asm3 A3 present
- #ol=obj.InListRecursive
- ol = get_sorted_list (obj)
- #print (ol)
- #print (len(ol))
- #to_add=ol[len(ol)-1].Name+','
- to_add=''
- #for i in range(len(ol),1,-1):
+ if hasattr(obj, "InListExRecursive"): # asm3 A3 present
+ # ol=obj.InListRecursive
+ ol = get_sorted_list(obj)
+ # print (ol)
+ # print (len(ol))
+ # to_add=ol[len(ol)-1].Name+','
+ to_add = ""
+ # for i in range(len(ol),1,-1):
for i in range(1, len(ol)):
- #to_add += ol[i-2].Name+'.'
- to_add += ol[i].Name+'.'
- to_add += obj.Name+'.'
- #to_add +=','
- #print (to_add);
- #print (str(ol[len(ol)-1].Name+','+to_add+','))
- #FreeCADGui.Selection.addSelection(ol[len(ol)-1],to_add,)
- #FreeCADGui.Selection.addSelection(obj)
- #get_Selected()
- #print (str(ol[0].Name+','+to_add+','))
- FreeCADGui.Selection.addSelection(ol[0],to_add,)
+ # to_add += ol[i-2].Name+'.'
+ to_add += ol[i].Name + "."
+ to_add += obj.Name + "."
+ # to_add +=','
+ # print (to_add);
+ # print (str(ol[len(ol)-1].Name+','+to_add+','))
+ # FreeCADGui.Selection.addSelection(ol[len(ol)-1],to_add,)
+ # FreeCADGui.Selection.addSelection(obj)
+ # get_Selected()
+ # print (str(ol[0].Name+','+to_add+','))
+ FreeCADGui.Selection.addSelection(
+ ol[0],
+ to_add,
+ )
else:
FreeCADGui.Selection.addSelection(obj)
- #stop
+ # stop
+
+
##
-def decimals(f,n):
- v = str(round(f,n))
- if '.' in v:
- if (len(v[v.find('.'):]) > n+1):
- v = v[:len(v)-1]
+
+def decimals(f, n):
+ v = str(round(f, n))
+ if "." in v and (len(v[v.find(".") :]) > n + 1):
+ v = v[: len(v) - 1]
return float(v)
+
def truncate(f, n):
- '''Truncates/pads a float f to n decimal places without rounding'''
- s = '{}'.format(f)
- if 'e' in s or 'E' in s:
- return '{0:.{1}f}'.format(f, n)
- i, p, d = s.partition('.')
- return '.'.join([i, (d+'0'*n)[:n]])
-
-def trunc (f,n):
- s=str(f)
- l=len(s)
- dp=(s.find('.'))
- if dp+n+1 < l:
- s=s[:dp+n+1]
+ """Truncates/pads a float f to n decimal places without rounding"""
+ s = f"{f}"
+ if "e" in s or "E" in s:
+ return "{0:.{1}f}".format(f, n)
+ i, _p, d = s.partition(".")
+ return ".".join([i, (d + "0" * n)[:n]])
+
+
+def trunc(f, n):
+ s = str(f)
+ l = len(s)
+ dp = s.find(".")
+ if dp + n + 1 < l:
+ s = s[: dp + n + 1]
return s
-
+
+
def roundMatrix(mtx):
- mtxR = [] #mtx
- for i, v in enumerate (mtx.A):
+ mtxR = [] # mtx
+ for i, v in enumerate(mtx.A):
n_dec = 4
- rv = str(round(v,n_dec))
- l=len(rv)
- if '.' in rv:
- if (len(rv[rv.find('.'):]) > n_dec):
- #print (rv);print (rv.find('.'))
- rv = rv[:l-1]
- #print (rv)
- rv = rv.replace('-0.0','0.0')
- #rv = truncate(v, 3)
- #rv = trunc(v,3)
+ rv = str(round(v, n_dec))
+ l = len(rv)
+ if "." in rv and (len(rv[rv.find(".") :]) > n_dec):
+ # print (rv);print (rv.find('.'))
+ rv = rv[: l - 1]
+ # print (rv)
+ rv = rv.replace("-0.0", "0.0")
+ # rv = truncate(v, 3)
+ # rv = trunc(v,3)
mtxR.append(float(rv))
- #mtxR.append(rv)
- #mtxR.append((str(rv).replace('-0.0','0.0')))
+ # mtxR.append(rv)
+ # mtxR.append((str(rv).replace('-0.0','0.0')))
return mtxR
+
+
###
-def roundEdge(edg):
- if 'Line' in str(edg):
- #print (str(edg))
- ps = edg.StartPoint; psx=round(ps.x,3);psy=round(ps.y,3);psz=round(ps.z,3)
- pe = edg.EndPoint; pex=round(pe.x,3);pey=round(pe.y,3);pez=round(pe.z,3)
- return PLine(Base.Vector(psx,psy,psz), Base.Vector(pex,pey,pez))
- elif 'ArcOfCircle' in str(edg):
- #print (str(edg))
- #v=FreeCAD.Vector
- c=edg.Center;cx=round(c[0],3);cy=round(c[1],3);cz=round(c[0],3);
- r=round(edg.Radius,3);axis=edg.Axis
- sa=round(edg.FirstParameter,4);ea=round(edg.LastParameter,4)
- return Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx,cy,cz),axis,r),sa,ea)
- elif 'Circle' in str(edg):
- #print (str(edg))
- c=edg.Center;cx=round(c[0],3);cy=round(c[1],3);cz=round(c[0],3);
- r=round(edg.Radius,3);axis=edg.Axis
- return Part.Circle(FreeCAD.Vector(cx,cy,cz),axis,r)
+def roundEdge(edg):
+ if "Line" in str(edg):
+ # print (str(edg))
+ ps = edg.StartPoint
+ psx = round(ps.x, 3)
+ psy = round(ps.y, 3)
+ psz = round(ps.z, 3)
+ pe = edg.EndPoint
+ pex = round(pe.x, 3)
+ pey = round(pe.y, 3)
+ pez = round(pe.z, 3)
+ return PLine(Base.Vector(psx, psy, psz), Base.Vector(pex, pey, pez))
+ if "ArcOfCircle" in str(edg):
+ # print (str(edg))
+ # v=FreeCAD.Vector
+ c = edg.Center
+ cx = round(c[0], 3)
+ cy = round(c[1], 3)
+ cz = round(c[0], 3)
+ r = round(edg.Radius, 3)
+ axis = edg.Axis
+ sa = round(edg.FirstParameter, 4)
+ ea = round(edg.LastParameter, 4)
+ return Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx, cy, cz), axis, r), sa, ea)
+ if "Circle" in str(edg):
+ # print (str(edg))
+ c = edg.Center
+ cx = round(c[0], 3)
+ cy = round(c[1], 3)
+ cz = round(c[0], 3)
+ r = round(edg.Radius, 3)
+ axis = edg.Axis
+ return Part.Circle(FreeCAD.Vector(cx, cy, cz), axis, r)
+ return None
+
+
##
-def roundVal(v,n_dec=None):
- #round to n_dec after '.'
+def roundVal(v, n_dec=None):
+ # round to n_dec after '.'
if n_dec is None:
n_dec = 3
- v=float(v)
- rv = str(round(v,n_dec+1))
- l=len(rv)
- if '.' in rv:
- if (len(rv[rv.find('.'):]) > n_dec+1):
- #print (rv);print (rv.find('.'))
- rv = rv[:l-1]
- #print (rv)
- rv = rv.replace('-0.0','0.0')
- #rv = truncate(v, 3)
- #rv = trunc(v,3)
- return(float(rv))
+ v = float(v)
+ rv = str(round(v, n_dec + 1))
+ l = len(rv)
+ if "." in rv and (len(rv[rv.find(".") :]) > n_dec + 1):
+ # print (rv);print (rv.find('.'))
+ rv = rv[: l - 1]
+ # print (rv)
+ rv = rv.replace("-0.0", "0.0")
+ # rv = truncate(v, 3)
+ # rv = trunc(v,3)
+ return float(rv)
+
+
###
def rmvSuffix(doc=None):
if doc is None:
doc = FreeCAD.ActiveDocument
for ob in doc.Objects:
- if ob.TypeId == 'App::Part' or ob.TypeId == 'App::LinkGroup':
- #suffix1 = '.stp';suffix2 = '.step';suffix3 = '_stp';suffix2 = '_step'
- #if ob.Label.lower().endswith(suffix1) or ob.Label.lower().endswith(suffix2)\
+ if ob.TypeId in {"App::Part", "App::LinkGroup"}:
+ # suffix1 = '.stp';suffix2 = '.step';suffix3 = '_stp';suffix2 = '_step'
+ # if ob.Label.lower().endswith(suffix1) or ob.Label.lower().endswith(suffix2)\
# or ob.Label.lower().endswith(suffix1) or ob.Label.lower().endswith(suffix2):
o_list = ob.OutListRecursive
for o in o_list:
- #print (o.Label)
- if (hasattr(o, 'Shape')) \
- and ('Axis' not in o.Label and 'Plane' not in o.Label and 'Sketch' not in o.Label):
- #suffix1 = '.stp';suffix2 = '.step'
- #if o.Label.lower().endswith(suffix1) or o.Label.lower().endswith(suffix2):
- o.Label = re.sub('.stp', '', o.Label, flags=re.IGNORECASE)
- o.Label = re.sub('.step', '', o.Label, flags=re.IGNORECASE)
- #print (o.Label)
- if o.TypeId == 'App::Part' or o.TypeId == 'App::LinkGroup':
- o.Label = re.sub('_stp', '', o.Label, flags=re.IGNORECASE)
- o.Label = re.sub('_step', '', o.Label, flags=re.IGNORECASE)
- o.Label = re.sub('.stp', '', o.Label, flags=re.IGNORECASE)
- o.Label = re.sub('.step', '', o.Label, flags=re.IGNORECASE)
+ # print (o.Label)
+ if (hasattr(o, "Shape")) and (
+ "Axis" not in o.Label and "Plane" not in o.Label and "Sketch" not in o.Label
+ ):
+ # suffix1 = '.stp';suffix2 = '.step'
+ # if o.Label.lower().endswith(suffix1) or o.Label.lower().endswith(suffix2):
+ o.Label = re.sub(".stp", "", o.Label, flags=re.IGNORECASE)
+ o.Label = re.sub(".step", "", o.Label, flags=re.IGNORECASE)
+ # print (o.Label)
+ if o.TypeId in {"App::Part", "App::LinkGroup"}:
+ o.Label = re.sub("_stp", "", o.Label, flags=re.IGNORECASE)
+ o.Label = re.sub("_step", "", o.Label, flags=re.IGNORECASE)
+ o.Label = re.sub(".stp", "", o.Label, flags=re.IGNORECASE)
+ o.Label = re.sub(".step", "", o.Label, flags=re.IGNORECASE)
for o in o_list:
- if (o.TypeId == 'App::Link'):
+ if o.TypeId == "App::Link":
o.Label = o.LinkedObject.Label
- FreeCAD.Console.PrintWarning('removed Suffix \'.stp\', \'.step\' \n')
+ FreeCAD.Console.PrintWarning("removed Suffix '.stp', '.step' \n")
+
+
##
-
+
+
def expPos(doc=None): ## export positions
if doc is None:
doc = FreeCAD.ActiveDocument
# rmvSuffix(doc)
- full_content=[]
- positions_content=[]
- sketch_content=[];sketch_content_header=[]
- #if doc is not None:
- if len(doc.FileName) == 0:
- docFn = 'File Not Saved'
- else:
- docFn = doc.FileName
- line='title: '+doc.Name
- full_content.append(line+'\n')
- line = 'FileN: '+docFn
- full_content.append(line+'\n')
+ full_content = []
+ positions_content = []
+ sketch_content = []
+ sketch_content_header = []
+ # if doc is not None:
+ docFn = "File Not Saved" if len(doc.FileName) == 0 else doc.FileName
+ line = "title: " + doc.Name
+ full_content.append(line + "\n")
+ line = "FileN: " + docFn
+ full_content.append(line + "\n")
print(line)
- line='date :'+str(datetime.datetime.now())
- full_content.append(line+'\n')
+ line = "date :" + str(datetime.datetime.now())
+ full_content.append(line + "\n")
print(line)
- line='3D models Placement ---------------'
- full_content.append(line+'\n')
+ line = "3D models Placement ---------------"
+ full_content.append(line + "\n")
print(line)
for o in doc.Objects:
# print(o.Name,o.Label,o.TypeId)
- if (hasattr(o, 'Shape') or o.TypeId == 'App::Link') and (hasattr(o, 'Placement')) and (o.TypeId != 'App::Line') and (o.TypeId != 'App::Plane'):
- if 'Sketch' not in o.Label and 'Pcb' not in o.Label:
- #print(o.Placement.Rotation.Q[3])
+ if (
+ (hasattr(o, "Shape") or o.TypeId == "App::Link")
+ and hasattr(o, "Placement")
+ and o.TypeId not in {"App::Line", "App::Plane"}
+ ):
+ if "Sketch" not in o.Label and "Pcb" not in o.Label:
+ # print(o.Placement.Rotation.Q[3])
# oPlacement = 'Placement [Pos=('+"{0:.2f}".format(o.Placement.Base.x,3)+','+"{0:.2f}".format(o.Placement.Base.y)+','+"{0:.2f}".format(o.Placement.Base.z)+\
# '), Yaw-Pitch-Roll=('+"{0:.2f}".format(o.Placement.Rotation.toEuler()[0]*qsign)+','+"{0:.2f}".format(o.Placement.Rotation.toEuler()[1])+\
# ','+"{0:.2f}".format(o.Placement.Rotation.toEuler()[2])+')]'
- #oPlacement=oPlacement.replace('-0.00','0.00')
+ # oPlacement=oPlacement.replace('-0.00','0.00')
if 0:
- oPl=str(o.Placement)
- Pos=oPl[oPl.find('(')+1:oPl.find(')')].split(',')
- PosN=[]
+ oPl = str(o.Placement)
+ Pos = oPl[oPl.find("(") + 1 : oPl.find(")")].split(",")
+ PosN = []
for p in Pos:
- p=float(p);PosN.append(p)
- Ypr=oPl[oPl.rfind('(')+1:oPl.rfind(')')].split(',')
- YprN=[]
+ p = float(p)
+ PosN.append(p)
+ Ypr = oPl[oPl.rfind("(") + 1 : oPl.rfind(")")].split(",")
+ YprN = []
for a in Ypr:
- a=float(a);YprN.append(a)
- oPlacement = 'Placement [Pos=('+"{0:.2f}".format(PosN[0])+','+"{0:.2f}".format(PosN[1])+','+"{0:.2f}".format(PosN[2])+','+\
- '), Yaw-Pitch-Roll=('+"{:.2f}".format(YprN[0])+','+"{:.2f}".format(YprN[1])+','+"{:.2f}".format(YprN[2])+')]'
- line=o.Label[:o.Label.find('_')]+','+oPlacement
- positions_content.append(line+'\n')
- line=o.Label[:o.Label.find('_')]+','+str(o.Placement)+' Q '+str(o.Placement.Rotation.Q)
- positions_content.append(line+'\n')
+ a = float(a)
+ YprN.append(a)
+ oPlacement = (
+ "Placement [Pos=("
+ + f"{PosN[0]:.2f}"
+ + ","
+ + f"{PosN[1]:.2f}"
+ + ","
+ + f"{PosN[2]:.2f}"
+ + ","
+ + "), Yaw-Pitch-Roll=("
+ + f"{YprN[0]:.2f}"
+ + ","
+ + f"{YprN[1]:.2f}"
+ + ","
+ + f"{YprN[2]:.2f}"
+ + ")]"
+ )
+ line = o.Label[: o.Label.find("_")] + "," + oPlacement
+ positions_content.append(line + "\n")
+ line = o.Label[: o.Label.find("_")] + "," + str(o.Placement) + " Q " + str(o.Placement.Rotation.Q)
+ positions_content.append(line + "\n")
# https://forum.freecadweb.org/viewtopic.php?f=8&t=25737&start=10
# line=o.Label[:o.Label.find('_')]+','+ str(o.Placement.toMatrix())
# positions_content.append(line+'\n')
# print (line)
- rMtx=roundMatrix(o.Placement.toMatrix())
- line=o.Label[:o.Label.find('_')]+', P.Mtx('+ str(rMtx)+')'
- positions_content.append(line+'\n')
- print (line)
- #if o.Label == 'PCB_Sketch':
- if 'PCB_Sketch_' in o.Label:
- line='Sketch geometry -------------------'
- sketch_content_header.append(line+'\n')
- print('Sketch geometry -------------------')
- if hasattr(o,'Geometry'):
- if hasattr(o,'GeometryFacadeList'):
+ rMtx = roundMatrix(o.Placement.toMatrix())
+ line = o.Label[: o.Label.find("_")] + ", P.Mtx(" + str(rMtx) + ")"
+ positions_content.append(line + "\n")
+ print(line)
+ # if o.Label == 'PCB_Sketch':
+ if "PCB_Sketch_" in o.Label:
+ line = "Sketch geometry -------------------"
+ sketch_content_header.append(line + "\n")
+ print("Sketch geometry -------------------")
+ if hasattr(o, "Geometry"):
+ if hasattr(o, "GeometryFacadeList"):
Gm = o.GeometryFacadeList
for e in Gm:
if not e.Construction:
- line=str(roundEdge(e.Geometry))
- sketch_content.append(line+'\n')
- #print (e)
+ line = str(roundEdge(e.Geometry))
+ sketch_content.append(line + "\n")
+ # print (e)
else:
for e in o.Geometry:
if not e.Construction:
- line=str(roundEdge(e))
- sketch_content.append(line+'\n')
- #print (e)
+ line = str(roundEdge(e))
+ sketch_content.append(line + "\n")
+ # print (e)
sketch_content.sort()
sketch_content[:0] = sketch_content_header
- line='-----------------------------------'
- sketch_content.append(line+'\n')
+ line = "-----------------------------------"
+ sketch_content.append(line + "\n")
print(line)
- #if o.Label == 'Pcb':
- if 'Pcb_' in o.Label:
- line='Pcb Volume -------------------'
- sketch_content.append(line+'\n')
+ # if o.Label == 'Pcb':
+ if "Pcb_" in o.Label:
+ line = "Pcb Volume -------------------"
+ sketch_content.append(line + "\n")
print(line)
vol = o.Shape.Volume
- vol = decimals(vol,3)
- line = 'Pcb Volume = ' + str(vol)
- sketch_content.append(line+'\n')
- print (line)
- line='-----------------------------------'
- sketch_content.append(line+'\n')
+ vol = decimals(vol, 3)
+ line = "Pcb Volume = " + str(vol)
+ sketch_content.append(line + "\n")
+ print(line)
+ line = "-----------------------------------"
+ sketch_content.append(line + "\n")
print(line)
positions_content.sort()
full_content.extend(positions_content)
full_content.extend(sketch_content)
- line='END of List -----------------------'
- full_content.append(line+'\n')
+ line = "END of List -----------------------"
+ full_content.append(line + "\n")
print(line)
- testing=False
+ testing = False
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
if not pg.IsEmpty():
- lastPath = pg.GetString('lastPath')
- if len(lastPath)==0:
+ lastPath = pg.GetString("lastPath")
+ if len(lastPath) == 0:
home = expanduser("~")
- pg.SetString('lastPath', home)
+ pg.SetString("lastPath", home)
else:
home = lastPath
if not testing:
- Filter=""
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- #print('native_dlg',prefs_.GetBool('native_dlg'))
- if not(prefs_.GetBool('not_native_dlg')):
- name, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Write 3D models & footprint positions to a Report file ...",
- home, "*.rpt")
+ # print('native_dlg',prefs_.GetBool('native_dlg'))
+ if not (prefs_.GetBool("not_native_dlg")):
+ name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName(
+ None,
+ "Write 3D models & footprint positions to a Report file ...",
+ home,
+ "*.rpt",
+ )
else:
- name, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Write 3D models & footprint positions to a Report file ...",
- home, "*.rpt",options=QtWidgets.QFileDialog.DontUseNativeDialog)
- #path, fname = os.path.split(name)
- #fname=os.path.splitext(fname)[0]
- #fpth = os.path.dirname(os.path.abspath(__file__))
+ name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName(
+ None,
+ "Write 3D models & footprint positions to a Report file ...",
+ home,
+ "*.rpt",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
+ # path, fname = os.path.split(name)
+ # fname=os.path.splitext(fname)[0]
+ # fpth = os.path.dirname(os.path.abspath(__file__))
if name:
lastPath = os.path.dirname(os.path.abspath(name))
- pg.SetString('lastPath', lastPath)
- else:
- if os.path.isdir("d:/Temp/"):
- name='d:/Temp/ex2.rpt'
- elif os.path.isdir("c:/Temp/"):
- name='c:/Temp/ex2.rpt'
- #say(name)
+ pg.SetString("lastPath", lastPath)
+ elif os.path.isdir("d:/Temp/"):
+ name = "d:/Temp/ex2.rpt"
+ elif os.path.isdir("c:/Temp/"):
+ name = "c:/Temp/ex2.rpt"
+ # say(name)
if name:
- #if os.path.exists(name):
- f = open(name, "w")
- f.write(''.join(full_content))
- f.close
+ # if os.path.exists(name):
+ with open(name, "w") as f:
+ f.write("".join(full_content))
+
##
def cmpPos(doc=None): ## compare exported positions with the selected doc
if doc is None:
doc = FreeCAD.ActiveDocument
# rmvSuffix(doc)
- full_content=[]
- positions_content=[]
- sketch_content=[];sketch_content_header=[]
- #if doc is not None:
- if len(doc.FileName) == 0:
- docFn = 'File Not Saved'
- else:
- docFn = doc.FileName
- line='title: '+doc.Name
- full_content.append(line+'\n')
- line = 'FileN: '+docFn
- full_content.append(line+'\n')
- #print(line)
- line='date :'+str(datetime.datetime.now())
- full_content.append(line+'\n')
- #print(line)
- line='3D models Placement ---------------'
- full_content.append(line+'\n')
- #print(line)
+ full_content = []
+ positions_content = []
+ sketch_content = []
+ sketch_content_header = []
+ # if doc is not None:
+ docFn = "File Not Saved" if len(doc.FileName) == 0 else doc.FileName
+ line = "title: " + doc.Name
+ full_content.append(line + "\n")
+ line = "FileN: " + docFn
+ full_content.append(line + "\n")
+ # print(line)
+ line = "date :" + str(datetime.datetime.now())
+ full_content.append(line + "\n")
+ # print(line)
+ line = "3D models Placement ---------------"
+ full_content.append(line + "\n")
+ # print(line)
for o in doc.Objects:
# print(o.Name,o.Label,o.TypeId)
- if (hasattr(o, 'Shape') or o.TypeId == 'App::Link') and (hasattr(o, 'Placement')) and (o.TypeId != 'App::Line') and (o.TypeId != 'App::Plane'):
- if 'Sketch' not in o.Label and 'Pcb' not in o.Label:
- #oPlacement = 'Placement [Pos=('+"{0:.3f}".format(o.Placement.Base.x)+','+"{0:.3f}".format(o.Placement.Base.y)+','+"{0:.3f}".format(o.Placement.Base.z)+\
+ if (
+ (hasattr(o, "Shape") or o.TypeId == "App::Link")
+ and hasattr(o, "Placement")
+ and o.TypeId not in {"App::Line", "App::Plane"}
+ ):
+ if "Sketch" not in o.Label and "Pcb" not in o.Label:
+ # oPlacement = 'Placement [Pos=('+"{0:.3f}".format(o.Placement.Base.x)+','+"{0:.3f}".format(o.Placement.Base.y)+','+"{0:.3f}".format(o.Placement.Base.z)+\
#'), Yaw-Pitch-Roll=('+"{0:.3f}".format(o.Placement.Rotation.toEuler()[0])+','+"{0:.3f}".format(o.Placement.Rotation.toEuler()[1])+','+"{0:.3f}".format(o.Placement.Rotation.toEuler()[2])+')]'
- #oPlacement = 'Placement [Pos=('+"{0:.2f}".format(o.Placement.Base.x)+','+"{0:.2f}".format(o.Placement.Base.y)+','+"{0:.2f}".format(o.Placement.Base.z)+\
+ # oPlacement = 'Placement [Pos=('+"{0:.2f}".format(o.Placement.Base.x)+','+"{0:.2f}".format(o.Placement.Base.y)+','+"{0:.2f}".format(o.Placement.Base.z)+\
#'), Yaw-Pitch-Roll=('+"{0:.2f}".format(o.Placement.Rotation.toEuler()[0])+','+"{0:.2f}".format(o.Placement.Rotation.toEuler()[1])+','+"{0:.2f}".format(o.Placement.Rotation.toEuler()[2])+')]'
- #oPlacement=oPlacement.replace('-0.00','0.00')
- #line=o.Label[:o.Label.find('_')]+','+oPlacement
+ # oPlacement=oPlacement.replace('-0.00','0.00')
+ # line=o.Label[:o.Label.find('_')]+','+oPlacement
# line=o.Label[:o.Label.find('_')]+','+ str(o.Placement.toMatrix())
# positions_content.append(line+'\n')
# print (line)
- rMtx=roundMatrix(o.Placement.toMatrix())
- line=o.Label[:o.Label.find('_')]+', P.Mtx('+ str(rMtx)+')'
- positions_content.append(line+'\n')
- #print (line)
+ rMtx = roundMatrix(o.Placement.toMatrix())
+ line = o.Label[: o.Label.find("_")] + ", P.Mtx(" + str(rMtx) + ")"
+ positions_content.append(line + "\n")
+ # print (line)
# if o.Label == 'PCB_Sketch':
- if 'PCB_Sketch_' in o.Label:
- line='Sketch geometry -------------------'
- sketch_content_header.append(line+'\n')
- #print('Sketch geometry -------------------')
- if hasattr(o,'Geometry'):
- if hasattr(o,'Geometry'):
- if hasattr(o,'GeometryFacadeList'):
- Gm = o.GeometryFacadeList
- for e in Gm:
- if not e.Construction:
- line=str(roundEdge(e.Geometry))
- sketch_content.append(line+'\n')
- #print (e)
- else:
- Gm = o.Geometry
- for e in Gm:
- if not e.Construction:
- line=str(roundEdge(e))
- sketch_content.append(line+'\n')
- #print (e)
+ if "PCB_Sketch_" in o.Label:
+ line = "Sketch geometry -------------------"
+ sketch_content_header.append(line + "\n")
+ # print('Sketch geometry -------------------')
+ if hasattr(o, "Geometry") and hasattr(o, "Geometry"):
+ if hasattr(o, "GeometryFacadeList"):
+ Gm = o.GeometryFacadeList
+ for e in Gm:
+ if not e.Construction:
+ line = str(roundEdge(e.Geometry))
+ sketch_content.append(line + "\n")
+ # print (e)
+ else:
+ Gm = o.Geometry
+ for e in Gm:
+ if not e.Construction:
+ line = str(roundEdge(e))
+ sketch_content.append(line + "\n")
+ # print (e)
sketch_content.sort()
sketch_content[:0] = sketch_content_header
- #sketch_content_header.extend(sketch_content)
- #sketch_content=[]
- #sketch_content=sketch_content_header
- line='-----------------------------------'
- sketch_content.append(line+'\n')
- #print(line)
+ # sketch_content_header.extend(sketch_content)
+ # sketch_content=[]
+ # sketch_content=sketch_content_header
+ line = "-----------------------------------"
+ sketch_content.append(line + "\n")
+ # print(line)
# if o.Label == 'Pcb':
- if 'Pcb_' in o.Label:
- line='Pcb Volume -------------------'
- sketch_content.append(line+'\n')
- #print(line)
+ if "Pcb_" in o.Label:
+ line = "Pcb Volume -------------------"
+ sketch_content.append(line + "\n")
+ # print(line)
vol = o.Shape.Volume
- vol = decimals(vol,3)
- line = 'Pcb Volume = ' + str(vol)
- sketch_content.append(line+'\n')
- #print (line)
- line='-----------------------------------'
- sketch_content.append(line+'\n')
- #print(line)
+ vol = decimals(vol, 3)
+ line = "Pcb Volume = " + str(vol)
+ sketch_content.append(line + "\n")
+ # print (line)
+ line = "-----------------------------------"
+ sketch_content.append(line + "\n")
+ # print(line)
positions_content.sort()
full_content.extend(positions_content)
full_content.extend(sketch_content)
- line='END of List -----------------------'
- full_content.append(line+'\n')
- #print(line)
- testing=False
+ line = "END of List -----------------------"
+ full_content.append(line + "\n")
+ # print(line)
+ testing = False
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
if not pg.IsEmpty():
- lastPath = pg.GetString('lastPath')
- if len(lastPath)==0:
+ lastPath = pg.GetString("lastPath")
+ if len(lastPath) == 0:
home = expanduser("~")
- pg.SetString('lastPath', home)
+ pg.SetString("lastPath", home)
else:
home = lastPath
- #home = expanduser("~")
- #home = r'C:\Cad\Progetti_K\board-revision\SolidWorks-2018-09-03_fede'
+ # home = expanduser("~")
+ # home = r'C:\Cad\Progetti_K\board-revision\SolidWorks-2018-09-03_fede'
if not testing:
- Filter=""
- prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- #print('native_dlg',prefs_.GetBool('native_dlg'))
- if not(prefs_.GetBool('not_native_dlg')):
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open 3D models & footprint positions Report file\nto compare positions with the Active Document...",
- home, "*.rpt")
+ # print('native_dlg',prefs_.GetBool('native_dlg'))
+ if not (prefs_.GetBool("not_native_dlg")):
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open 3D models & footprint positions Report file\nto compare positions with the Active Document...",
+ home,
+ "*.rpt",
+ )
else:
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open 3D models & footprint positions Report file\nto compare positions with the Active Document...",
- home, "*.rpt",options=QtWidgets.QFileDialog.DontUseNativeDialog)
- #path, fname = os.path.split(name)
- #fname=os.path.splitext(fname)[0]
- #fpth = os.path.dirname(os.path.abspath(__file__))
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open 3D models & footprint positions Report file\nto compare positions with the Active Document...",
+ home,
+ "*.rpt",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
+ # path, fname = os.path.split(name)
+ # fname=os.path.splitext(fname)[0]
+ # fpth = os.path.dirname(os.path.abspath(__file__))
if name:
lastPath = os.path.dirname(os.path.abspath(name))
- pg.SetString('lastPath', lastPath)
- else:
- if os.path.isdir("d:/Temp/"):
- name='d:/Temp/ex2.rpt'
- elif os.path.isdir("c:/Temp/"):
- name='c:/Temp/ex2.rpt'
- #say(name)
+ pg.SetString("lastPath", lastPath)
+ elif os.path.isdir("d:/Temp/"):
+ name = "d:/Temp/ex2.rpt"
+ elif os.path.isdir("c:/Temp/"):
+ name = "c:/Temp/ex2.rpt"
+ # say(name)
if os.path.exists(name):
with open(name) as a:
a_content = a.readlines()
b_content = full_content
- #print (a_content);print ('-----------b_c----------');print (b_content);stop
- diff = difflib.unified_diff(a_content,b_content)
- diff_content=[]
- diff_list=[]
- sk_add=[]
- sk_sub=[]
- header="***** Unified diff ************"
- diff_content.append(header+os.linesep)
- #print(header)
- header1="Line no"+5*' '+'previous'+5*' '+'updated'
- #print("Line no"+'\t'+'file1'+'\t'+'file2')
- #print(header1)
- diff_content.append(header1+os.linesep)
- for i,line in enumerate(diff):
+ # print (a_content);print ('-----------b_c----------');print (b_content);stop
+ diff = difflib.unified_diff(a_content, b_content)
+ diff_content = []
+ diff_list = []
+ sk_add = []
+ sk_sub = []
+ header = "***** Unified diff ************"
+ diff_content.append(header + os.linesep)
+ # print(header)
+ header1 = "Line no" + 5 * " " + "previous" + 5 * " " + "updated"
+ # print("Line no"+'\t'+'file1'+'\t'+'file2')
+ # print(header1)
+ diff_content.append(header1 + os.linesep)
+ for i, line in enumerate(diff):
if line.startswith("-"):
- if not line.startswith("---") and not line.startswith("-title") \
- and not line.startswith("-FileN") and not line.startswith("-date "):
- #print(i,'\t\t'+line)
- #print('Ln '+str(i)+(8-(len(str(i))))*' '),(line),
- diff_content.append('Ln '+str(i)+(8-len(str(i)))*' '+line)
- if line.startswith('-','')
- p1 = points[:points.find(')')].split(',')
- p2 = points[points.rfind('(')+1:-1].split(',')
- sk_sub.append(PLine(Base.Vector(round(float(p1[0]),3),round(float(p1[1]),3),round(float(p1[2]),3)), Base.Vector(float(p2[0]),float(p2[1]),float(p2[2]))))
- elif line.startswith('-ArcOfCircle'):
- data=line.replace('-ArcOfCircle (Radius : ','').replace('))\n','')
- data=data.split(':')
- radius = data[0].split(',')[0]
- pos = data[1][data[1].find('(')+1:data[1].find(')')].split(',')
- dir = data[2][data[2].find('(')+1:data[2].rfind(')')].split(',')
- par = data[3][data[3].find('(')+1:].split(',')
- #print (radius,pos,dir,par);stop
- sk_sub.append(Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(round(float(pos[0]),3),round(float(pos[1]),3),round(float(pos[2]),3)),FreeCAD.Vector(float(dir[0]),float(dir[1]),float(dir[2])),round(float(radius),3)),round(float(par[0]),5),round(float(par[1]),5)))
- elif line.startswith('-Circle'):
- data=line.replace('-Circle (Radius : ','').replace('))\n','')
- data=data.split(':')
- radius = data[0].split(',')[0]
- pos = data[1][data[1].find('(')+1:data[1].find(')')].split(',')
- dir = data[2][data[2].find('(')+1:].split(',')
- print (radius,pos,dir)
- sk_sub.append(Part.Circle(FreeCAD.Vector(round(float(pos[0]),3),round(float(pos[1]),3),round(float(pos[2]),3)),FreeCAD.Vector(float(dir[0]),float(dir[1]),float(dir[2])),round(float(radius),3)))
- elif line.startswith("+"):
- if not line.startswith("+++") and not line.startswith("+title") \
- and not line.startswith("+FileN") and not line.startswith("+date "):
- #print(i,'\t\t'+line)
- #print('Ln '+str(i)+(8-(len(str(i))))*' '),(line),
- diff_content.append('Ln '+str(i)+(8-len(str(i)))*' '+line)
- diff_list.append(line[1:])
- if line.startswith('+','')
- p1 = points[:points.find(')')].split(',')
- p2 = points[points.rfind('(')+1:-1].split(',')
- sk_add.append(PLine(Base.Vector(float(p1[0]),float(p1[1]),float(p1[2])), Base.Vector(float(p2[0]),float(p2[1]),float(p2[2]))))
- # sk_add.append(line.replace('+',''))
- elif line.startswith('+ArcOfCircle'):
- data=line.replace('+ArcOfCircle (Radius : ','').replace('))\n','')
- data=data.split(':')
- radius = data[0].split(',')[0]
- pos = data[1][data[1].find('(')+1:data[1].find(')')].split(',')
- dir = data[2][data[2].find('(')+1:data[2].rfind(')')].split(',')
- par = data[3][data[3].find('(')+1:].split(',')
- #print (radius,pos,dir,par);stop
- sk_add.append(Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(float(pos[0]),float(pos[1]),float(pos[2])),FreeCAD.Vector(float(dir[0]),float(dir[1]),float(dir[2])),float(radius)),float(par[0]),float(par[1])))
- elif line.startswith('+Circle'):
- data=line.replace('+Circle (Radius : ','').replace('))\n','')
- data=data.split(':')
- radius = data[0].split(',')[0]
- pos = data[1][data[1].find('(')+1:data[1].find(')')].split(',')
- dir = data[2][data[2].find('(')+1:].split(',')
- print (radius,pos,dir)
- sk_add.append(Part.Circle(FreeCAD.Vector(float(pos[0]),float(pos[1]),float(pos[2])),FreeCAD.Vector(float(dir[0]),float(dir[1]),float(dir[2])),float(radius)))
- #for d in (diff_content):
+ if (
+ not line.startswith("---")
+ and not line.startswith("-title")
+ and not line.startswith("-FileN")
+ and not line.startswith("-date ")
+ ):
+ # print(i,'\t\t'+line)
+ # print('Ln '+str(i)+(8-(len(str(i))))*' '),(line),
+ diff_content.append("Ln " + str(i) + (8 - len(str(i))) * " " + line)
+ if line.startswith("-", "")
+ p1 = points[: points.find(")")].split(",")
+ p2 = points[points.rfind("(") + 1 : -1].split(",")
+ sk_sub.append(
+ PLine(
+ Base.Vector(round(float(p1[0]), 3), round(float(p1[1]), 3), round(float(p1[2]), 3)),
+ Base.Vector(float(p2[0]), float(p2[1]), float(p2[2])),
+ ),
+ )
+ elif line.startswith("-ArcOfCircle"):
+ data = line.replace("-ArcOfCircle (Radius : ", "").replace("))\n", "")
+ data = data.split(":")
+ radius = data[0].split(",")[0]
+ pos = data[1][data[1].find("(") + 1 : data[1].find(")")].split(",")
+ dir = data[2][data[2].find("(") + 1 : data[2].rfind(")")].split(",")
+ par = data[3][data[3].find("(") + 1 :].split(",")
+ # print (radius,pos,dir,par);stop
+ sk_sub.append(
+ Part.ArcOfCircle(
+ Part.Circle(
+ FreeCAD.Vector(
+ round(float(pos[0]), 3),
+ round(float(pos[1]), 3),
+ round(float(pos[2]), 3),
+ ),
+ FreeCAD.Vector(float(dir[0]), float(dir[1]), float(dir[2])),
+ round(float(radius), 3),
+ ),
+ round(float(par[0]), 5),
+ round(float(par[1]), 5),
+ ),
+ )
+ elif line.startswith("-Circle"):
+ data = line.replace("-Circle (Radius : ", "").replace("))\n", "")
+ data = data.split(":")
+ radius = data[0].split(",")[0]
+ pos = data[1][data[1].find("(") + 1 : data[1].find(")")].split(",")
+ dir = data[2][data[2].find("(") + 1 :].split(",")
+ print(radius, pos, dir)
+ sk_sub.append(
+ Part.Circle(
+ FreeCAD.Vector(
+ round(float(pos[0]), 3),
+ round(float(pos[1]), 3),
+ round(float(pos[2]), 3),
+ ),
+ FreeCAD.Vector(float(dir[0]), float(dir[1]), float(dir[2])),
+ round(float(radius), 3),
+ ),
+ )
+ elif line.startswith("+") and (
+ not line.startswith("+++")
+ and not line.startswith("+title")
+ and not line.startswith("+FileN")
+ and not line.startswith("+date ")
+ ):
+ # print(i,'\t\t'+line)
+ # print('Ln '+str(i)+(8-(len(str(i))))*' '),(line),
+ diff_content.append("Ln " + str(i) + (8 - len(str(i))) * " " + line)
+ diff_list.append(line[1:])
+ if line.startswith("+", "")
+ p1 = points[: points.find(")")].split(",")
+ p2 = points[points.rfind("(") + 1 : -1].split(",")
+ sk_add.append(
+ PLine(
+ Base.Vector(float(p1[0]), float(p1[1]), float(p1[2])),
+ Base.Vector(float(p2[0]), float(p2[1]), float(p2[2])),
+ ),
+ )
+ # sk_add.append(line.replace('+',''))
+ elif line.startswith("+ArcOfCircle"):
+ data = line.replace("+ArcOfCircle (Radius : ", "").replace("))\n", "")
+ data = data.split(":")
+ radius = data[0].split(",")[0]
+ pos = data[1][data[1].find("(") + 1 : data[1].find(")")].split(",")
+ dir = data[2][data[2].find("(") + 1 : data[2].rfind(")")].split(",")
+ par = data[3][data[3].find("(") + 1 :].split(",")
+ # print (radius,pos,dir,par);stop
+ sk_add.append(
+ Part.ArcOfCircle(
+ Part.Circle(
+ FreeCAD.Vector(float(pos[0]), float(pos[1]), float(pos[2])),
+ FreeCAD.Vector(float(dir[0]), float(dir[1]), float(dir[2])),
+ float(radius),
+ ),
+ float(par[0]),
+ float(par[1]),
+ ),
+ )
+ elif line.startswith("+Circle"):
+ data = line.replace("+Circle (Radius : ", "").replace("))\n", "")
+ data = data.split(":")
+ radius = data[0].split(",")[0]
+ pos = data[1][data[1].find("(") + 1 : data[1].find(")")].split(",")
+ dir = data[2][data[2].find("(") + 1 :].split(",")
+ print(radius, pos, dir)
+ sk_add.append(
+ Part.Circle(
+ FreeCAD.Vector(float(pos[0]), float(pos[1]), float(pos[2])),
+ FreeCAD.Vector(float(dir[0]), float(dir[1]), float(dir[2])),
+ float(radius),
+ ),
+ )
+ # for d in (diff_content):
# print (d)
- #for d in (diff_list):
+ # for d in (diff_list):
# print(d)
- #diff_content = a_content + b_content
+ # diff_content = a_content + b_content
try:
- f = open(home+"\list_diff.lst", "w")
- f.write(''.join(diff_content))
- f.close
+ with open(home + r"\list_diff.lst", "w") as f:
+ f.write("".join(diff_content))
except:
- FreeCAD.Console.PrintError('Error in write permission for \'list_diff.lst\' report file.\n')
+ FreeCAD.Console.PrintError("Error in write permission for 'list_diff.lst' report file.\n")
FreeCADGui.Selection.clearSelection()
- nObj=0;old_pcb_tval=100;pcbN=''
- diff_objs=[]
- generate_sketch=False
+ nObj = 0
+ old_pcb_tval = 100
+ pcbN = ""
+ diff_objs = []
+ generate_sketch = False
for o in doc.Objects:
- if hasattr(o, 'Shape') or o.TypeId == 'App::Link':
- if 'Sketch' not in o.Label and 'Pcb' not in o.Label:
+ if hasattr(o, "Shape") or o.TypeId == "App::Link":
+ if "Sketch" not in o.Label and "Pcb" not in o.Label:
for changed in diff_list:
- if not changed[0].startswith('date'):
- ref = changed.split(',')[0]
- if o.Label.startswith(ref+'_'):
- #FreeCADGui.Selection.addSelection(o)
+ if not changed[0].startswith("date"):
+ ref = changed.split(",")[0]
+ if o.Label.startswith(ref + "_"):
+ # FreeCADGui.Selection.addSelection(o)
gui_addSelection(o)
diff_objs.append(o)
- #FreeCAD.Console.PrintWarning(o.Label+'\n') #;print('selected')
- nObj+=1
- if 'Sketch' not in o.Label and 'Pcb' in o.Label:
+ # FreeCAD.Console.PrintWarning(o.Label+'\n') #;print('selected')
+ nObj += 1
+ if "Sketch" not in o.Label and "Pcb" in o.Label:
old_pcb_tval = FreeCADGui.ActiveDocument.getObject(o.Name).Transparency
FreeCADGui.ActiveDocument.getObject(o.Name).Transparency = 70
- pcbN=o.Name
- if 'PCB_Sketch' in o.Label and 'Sketch' in o.TypeId:
- generate_sketch=True
- #print(''.join(diff_content)); stop
+ pcbN = o.Name
+ if "PCB_Sketch" in o.Label and "Sketch" in o.TypeId:
+ generate_sketch = True
+ # print(''.join(diff_content)); stop
if nObj > 0:
- dc = ''.join(diff_content)
+ dc = "".join(diff_content)
print(dc)
for o in diff_objs:
- FreeCAD.Console.PrintWarning(o.Label+'\n')
- FreeCAD.Console.PrintError('N.'+str(nObj)+' Object(s) with changed placement \'Selected\'\n')
- #print ('Circle' in diff_content)
- if dc.find('Circle')!=-1 or dc.find('Line segment')!=-1: # or dc.find('ArcOfCircle')!=-1:
- FreeCAD.Console.PrintError('*** \'Pcb Sketch\' modified! ***\n')
+ FreeCAD.Console.PrintWarning(o.Label + "\n")
+ FreeCAD.Console.PrintError("N." + str(nObj) + " Object(s) with changed placement 'Selected'\n")
+ # print ('Circle' in diff_content)
+ if dc.find("Circle") != -1 or dc.find("Line segment") != -1: # or dc.find('ArcOfCircle')!=-1:
+ FreeCAD.Console.PrintError("*** 'Pcb Sketch' modified! ***\n")
elif len(diff_content) > 3:
- FreeCAD.Console.PrintError('\'Pcb Sketch\' modified!\n')
- #for d in (diff_content):
+ FreeCAD.Console.PrintError("'Pcb Sketch' modified!\n")
+ # for d in (diff_content):
# print (d)
- #print(''.join(diff_content))
- if len(pcbN)>0:
+ # print(''.join(diff_content))
+ if len(pcbN) > 0:
FreeCADGui.ActiveDocument.getObject(pcbN).Transparency = old_pcb_tval
else:
- FreeCAD.Console.PrintWarning('no changes\n')
- if len(pcbN)>0:
+ FreeCAD.Console.PrintWarning("no changes\n")
+ if len(pcbN) > 0:
FreeCADGui.ActiveDocument.getObject(pcbN).Transparency = old_pcb_tval
- generateSketch = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetBool('generate_sketch')
+ generateSketch = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetBool(
+ "generate_sketch",
+ )
if generate_sketch and generateSketch:
- if len(sk_add)>0:
- #print(sk_add)
+ if len(sk_add) > 0:
+ # print(sk_add)
if FreeCAD.activeDocument().getObject("Sketch_Addition") is not None:
FreeCAD.activeDocument().removeObject("Sketch_Addition")
- Sketch_Addition = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Sketch_Addition')
- FreeCADGui.activeDocument().getObject("Sketch_Addition").LineColor = (0.000,0.000,1.000)
- FreeCADGui.activeDocument().getObject("Sketch_Addition").PointColor = (0.000,0.000,1.000)
+ Sketch_Addition = FreeCAD.activeDocument().addObject("Sketcher::SketchObject", "Sketch_Addition")
+ FreeCADGui.activeDocument().getObject("Sketch_Addition").LineColor = (0.000, 0.000, 1.000)
+ FreeCADGui.activeDocument().getObject("Sketch_Addition").PointColor = (0.000, 0.000, 1.000)
Sketch_Addition.Geometry = sk_add
- if len(sk_sub)>0:
- #print(sk_sub)
+ if len(sk_sub) > 0:
+ # print(sk_sub)
if FreeCAD.activeDocument().getObject("Sketch_Subtraction") is not None:
FreeCAD.activeDocument().removeObject("Sketch_Subtraction")
- Sketch_Subtraction = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Sketch_Subtraction')
- FreeCADGui.activeDocument().getObject("Sketch_Subtraction").LineColor = (0.667,0.000,0.498)
- FreeCADGui.activeDocument().getObject("Sketch_Subtraction").PointColor = (0.667,0.000,0.498)
+ Sketch_Subtraction = FreeCAD.activeDocument().addObject("Sketcher::SketchObject", "Sketch_Subtraction")
+ FreeCADGui.activeDocument().getObject("Sketch_Subtraction").LineColor = (0.667, 0.000, 0.498)
+ FreeCADGui.activeDocument().getObject("Sketch_Subtraction").PointColor = (0.667, 0.000, 0.498)
Sketch_Subtraction.Geometry = sk_sub
- if len(sk_add)>0 or len(sk_sub)>0:
+ if len(sk_add) > 0 or len(sk_sub) > 0:
FreeCAD.ActiveDocument.recompute()
+
## https://stackoverflow.com/questions/3605680/creating-a-simple-xml-file-using-python
-
class RemoveSuffixDlg(QtGui.QDialog):
-
- def __init__(self, parent= None):
- super(RemoveSuffixDlg, self).__init__(parent, QtCore.Qt.WindowStaysOnTopHint)
- #QtGui.QMainWindow.__init__(self, None, QtCore.Qt.WindowStaysOnTopHint)
- #icon = style.standardIcon(
+ def __init__(self, parent=None):
+ super().__init__(parent, QtCore.Qt.WindowStaysOnTopHint)
+ # QtGui.QMainWindow.__init__(self, None, QtCore.Qt.WindowStaysOnTopHint)
+ # icon = style.standardIcon(
# QtGui.QStyle.SP_MessageBoxCritical, None, widget)
- #self.setWindowIcon(self.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical))
- #self.setIcon(self.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical))
- #self.setIcon(self.style().standardIcon(QStyle.SP_DirIcon))
- #QtGui.QIcon(QtGui.QMessageBox.Critical))
- #icon = QtGui.QIcon()
- #icon.addPixmap(QtGui.QPixmap("icons/157-stats-bars.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
- #Widget.setWindowIcon(icon)
+ # self.setWindowIcon(self.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical))
+ # self.setIcon(self.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical))
+ # self.setIcon(self.style().standardIcon(QStyle.SP_DirIcon))
+ # QtGui.QIcon(QtGui.QMessageBox.Critical))
+ # icon = QtGui.QIcon()
+ # icon.addPixmap(QtGui.QPixmap("icons/157-stats-bars.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+ # Widget.setWindowIcon(icon)
ksuWBpath = os.path.dirname(ksu_locator.__file__)
- ksuWB_icons_path = os.path.join( ksuWBpath, 'Resources', 'icons')
-
- self.pix = QtGui.QLabel()
- self.pix.setText('')
- self.pix.setText('')
- self.pix.setPixmap(QtGui.QPixmap(ksuWB_icons_path+'/warning.svg'))
+ ksuWB_icons_path = os.path.join(ksuWBpath, "Resources", "icons")
+
+ self.pix = QtGui.QLabel()
+ self.pix.setText("")
+ self.pix.setText("")
+ self.pix.setPixmap(QtGui.QPixmap(ksuWB_icons_path + "/warning.svg"))
self.pix.setObjectName("pix")
- self.txt = QtGui.QLabel()
+ self.txt = QtGui.QLabel()
self.txt.setText("This will remove ALL Suffix from selection objects. \nDo you want to continue?")
-
- self.txt2 = QtGui.QLabel()
- self.txt2.setText("\'suffix\'")
+
+ self.txt2 = QtGui.QLabel()
+ self.txt2.setText("'suffix'")
self.le = QtGui.QLineEdit()
self.le.setObjectName("suffix_filter")
self.le.setText(".step")
self.le.setToolTip("change the text to be\nstripped out from the end of Labels")
-
- #self.pb = QtGui.QPushButton()
- #self.pb.setObjectName("OK")
- #self.pb.setText("OK")
+
+ # self.pb = QtGui.QPushButton()
+ # self.pb.setObjectName("OK")
+ # self.pb.setText("OK")
#
- #self.pbC = QtGui.QPushButton()
- #self.pbC.setObjectName("Cancel")
- #self.pbC.setText("Cancel")
-
+ # self.pbC = QtGui.QPushButton()
+ # self.pbC.setObjectName("Cancel")
+ # self.pbC.setText("Cancel")
+
self.buttonBox = QtGui.QDialogButtonBox()
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
- self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
+ self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
-
+
layout2 = QtGui.QHBoxLayout()
layout2.addWidget(self.pix)
layout2.addWidget(self.txt)
-
+
layout3 = QtGui.QHBoxLayout()
- #layout3.addWidget(self.pb)
- #layout3.addWidget(self.pbC)
-
-
+ # layout3.addWidget(self.pb)
+ # layout3.addWidget(self.pbC)
+
layout = QtGui.QVBoxLayout()
layout.addLayout(layout2)
layout.addWidget(self.txt2)
layout.addWidget(self.le)
layout.addLayout(layout3)
layout.addWidget(self.buttonBox)
-
- #layout.addWidget(self.pb)
- #layout.addWidget(self.pbC)
-
+
+ # layout.addWidget(self.pb)
+ # layout.addWidget(self.pbC)
+
self.setWindowTitle("Warning ...")
- #self.setWindowIcon(self.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical))
-
+ # self.setWindowIcon(self.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical))
+
self.setLayout(layout)
- #self.setLayout(layout)
- #self.connect(self.pb, QtCore.SIGNAL("clicked()"),self.OK_click)
- #self.connect(self.pbC, QtCore.SIGNAL("clicked()"),self.Cancel_click)
-
+ # self.setLayout(layout)
+ # self.connect(self.pb, QtCore.SIGNAL("clicked()"),self.OK_click)
+ # self.connect(self.pbC, QtCore.SIGNAL("clicked()"),self.Cancel_click)
+
self.buttonBox.button(QtGui.QDialogButtonBox.Ok).clicked.connect(self.OK_click)
self.buttonBox.button(QtGui.QDialogButtonBox.Cancel).clicked.connect(self.Cancel_click)
-
-
+
def OK_click(self):
# shost is a QString object
- filtered = self.le.text()
- #print (self.le.text())
- #return (QtGui.QMessageBox.Ok)
- #self.close()*
+ self.le.text()
+ # print (self.le.text())
+ # return (QtGui.QMessageBox.Ok)
+ # self.close()*
self.accept()
-
+
def Cancel_click(self):
# shost is a QString object
- #filtered = '.stp'
- self.le.setText('')
+ # filtered = '.stp'
+ self.le.setText("")
# print (filtered)
- #return (QtGui.QMessageBox.Cancel)
- #self.close()*
+ # return (QtGui.QMessageBox.Cancel)
+ # self.close()*
self.close()
-
diff --git a/expTree.py b/expTree.py
index 59f7b16..b45388a 100644
--- a/expTree.py
+++ b/expTree.py
@@ -1,70 +1,79 @@
-# -*- coding: utf-8 -*-
#
# Expands selected tree and all sub trees in the tree view.
# if selected tree is already expanded this tree and all sub trees are collapsed
#
# Author: wmayer
-import FreeCAD, FreeCADGui
+import FreeCADGui
from PySide import QtGui
-#from PySide.QtGui import QTreeWidgetItemIterator
+
+# from PySide.QtGui import QTreeWidgetItemIterator
+
def toggleAllSel(tree, item, collapse):
- if collapse == False:
+ if not collapse:
tree.expandItem(item)
- elif collapse == True:
+ elif collapse:
tree.collapseItem(item)
for i in range(item.childCount()):
- #print(item.child(i).text(0))
- if 'Origin' not in item.child(i).text(0):
+ # print(item.child(i).text(0))
+ if "Origin" not in item.child(i).text(0):
toggleAllSel(tree, item.child(i), collapse)
+
+
##
-def toggle_Tree():
+def toggle_Tree():
mw1 = FreeCADGui.getMainWindow()
treesSel = mw1.findChildren(QtGui.QTreeWidget)
-
+
for tree in treesSel:
items = tree.selectedItems()
for item in items:
- if item.isExpanded() == True:
+ if item.isExpanded():
collapse = True
- print ("collapsing")
+ print("collapsing")
else:
- print ("expanding")
- collapse = False
+ print("expanding")
+ collapse = False
toggleAllSel(tree, item, collapse)
+
+
##
-def collS_Tree():
- # collapse selected
+
+def collS_Tree():
+ # collapse selected
mw1 = FreeCADGui.getMainWindow()
treesSel = mw1.findChildren(QtGui.QTreeWidget)
-
+
for tree in treesSel:
items = tree.selectedItems()
for item in items:
- if item.isExpanded() == True:
- collapse = True
- print ("collapsing")
+ if item.isExpanded():
+ print("collapsing")
tree.collapseItem(item)
- #else:
+ # else:
# print ("expanding")
- # collapse = False
+ # collapse = False
+
+
##
-def expS_Tree():
- # expand selected
+
+def expS_Tree():
+ # expand selected
mw1 = FreeCADGui.getMainWindow()
treesSel = mw1.findChildren(QtGui.QTreeWidget)
-
+
for tree in treesSel:
items = tree.selectedItems()
for item in items:
- if item.isExpanded() == False:
- collapse = False
- print ("expanding")
+ if not item.isExpanded():
+ print("expanding")
tree.expandItem(item)
- #else:
+ # else:
# print ("expanding")
- # collapse = False
+ # collapse = False
+
+
##
diff --git a/explode.py b/explode.py
index 415819f..d5259ad 100644
--- a/explode.py
+++ b/explode.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
# Form implementation generated from reading ui file 'C:\Cad\Progetti_K\3D-FreeCad-tools\explode.ui'
#
# Created: Fri Sep 21 14:09:48 2018
@@ -9,58 +7,68 @@
__version__ = "v1.0.6"
-import FreeCAD, FreeCADGui, os
-from PySide import QtCore, QtGui
+import os
from sys import platform as _platform
+import FreeCADGui
+from PySide import QtCore, QtGui
+
global s # selection observer
global instance_nbr, explode_dwg
-instance_nbr=0
+instance_nbr = 0
# window GUI dimensions parameters
-wdsExpx=300;wdsExpy=140
-pt_osx=False
+wdsExpx = 300
+wdsExpy = 140
+pt_osx = False
if _platform == "linux" or _platform == "linux2":
# linux
- sizeX=wdsExpx;sizeY=wdsExpy-22+34 #516 #536
+ sizeX = wdsExpx
+ sizeY = wdsExpy - 22 + 34 # 516 #536
else:
- sizeX=wdsExpx;sizeY=wdsExpy-22 #482#502
+ sizeX = wdsExpx
+ sizeY = wdsExpy - 22 # 482#502
if _platform == "darwin":
- pt_osx=True
+ pt_osx = True
## # MAC OS X
##elif _platform == "win32":
## # Windows
toBeReset = None
-btn_iconsize=28
+btn_iconsize = 28
+
+import contextlib
import ksu_locator
+
ksuWBpath = os.path.dirname(ksu_locator.__file__)
-#sys.path.append(ksuWB + '/Gui')
-ksuWB_icons_path = os.path.join( ksuWBpath, 'Resources', 'icons')
+# sys.path.append(ksuWB + '/Gui')
+ksuWB_icons_path = os.path.join(ksuWBpath, "Resources", "icons")
+
-def get_top_level (obj):
- lvl=10000
- top=None
+def get_top_level(obj):
+ lvl = 10000
+ top = None
for ap in obj.InListRecursive:
- if hasattr(ap,'Placement') and ap.TypeId!='App::FeaturePython' and ap.TypeId!='Part::Part2DObjectPython':
+ if hasattr(ap, "Placement") and ap.TypeId not in {"App::FeaturePython", "Part::Part2DObjectPython"}:
if len(ap.InListRecursive) < lvl:
top = ap
lvl = len(ap.InListRecursive)
- if top is None:
- if 'App::Part' in obj.TypeId or 'App::LinkGroup' in obj.TypeId:
- top = obj
+ if top is None and ("App::Part" in obj.TypeId or "App::LinkGroup" in obj.TypeId):
+ top = obj
return top
+
+
###
class expSelectionObserver:
- def addSelection(self,document, object, element, position):
+ def addSelection(self, document, object, element, position):
"""Add single object to selection. Usually gets called when selecting in the 3d view"""
global explode_dwg
sel = FreeCADGui.Selection.getSelection()
- if len (sel)== 1:
+ if len(sel) == 1:
tlo = get_top_level(sel[0])
if tlo is not None:
- #if 'App::Part' in sel[0].TypeId:
+ # if 'App::Part' in sel[0].TypeId:
explode_dwg.ui.hSlider_explode.setEnabled(True)
else:
explode_dwg.ui.hSlider_explode.setEnabled(False)
@@ -70,61 +78,64 @@ def addSelection(self,document, object, element, position):
# FreeCAD.Console.PrintMessage(str(position)+"\n")
# ...
- def removeSelection(self,document, object, element):
+ def removeSelection(self, document, object, element):
"""Remove single object from selection. Usually gets called when deselecting in the 3d view"""
global explode_dwg
sel = FreeCADGui.Selection.getSelection()
- if len (sel)== 1:
+ if len(sel) == 1:
tlo = get_top_level(sel[0])
if tlo is not None:
- #if 'App::Part' in sel[0].TypeId:
+ # if 'App::Part' in sel[0].TypeId:
explode_dwg.ui.hSlider_explode.setEnabled(True)
else:
explode_dwg.ui.hSlider_explode.setEnabled(False)
- #FreeCAD.Console.PrintMessage(document+"\n")
- #FreeCAD.Console.PrintMessage(object+"\n")
- #FreeCAD.Console.PrintMessage(element+"\n")
+ # FreeCAD.Console.PrintMessage(document+"\n")
+ # FreeCAD.Console.PrintMessage(object+"\n")
+ # FreeCAD.Console.PrintMessage(element+"\n")
# ...
- def setSelection(self,document):
+ def setSelection(self, document):
"""Add one or more objects to selection. Usually gets called when selecting in the tree view"""
global explode_dwg
sel = FreeCADGui.Selection.getSelection()
- if len (sel)== 1:
+ if len(sel) == 1:
tlo = get_top_level(sel[0])
if tlo is not None:
- #if 'App::Part' in sel[0].TypeId:
+ # if 'App::Part' in sel[0].TypeId:
explode_dwg.ui.hSlider_explode.setEnabled(True)
else:
explode_dwg.ui.hSlider_explode.setEnabled(False)
- #FreeCAD.Console.PrintMessage(document+"\n")
- #selection=Gui.Selection.getSelection(document)
+ # FreeCAD.Console.PrintMessage(document+"\n")
+ # selection=Gui.Selection.getSelection(document)
# ...
- def clearSelection(self,document):
+ def clearSelection(self, document):
"""Remove all objects of the given document from the selection"""
global explode_dwg
sel = FreeCADGui.Selection.getSelection()
- if len (sel)== 1:
+ if len(sel) == 1:
tlo = get_top_level(sel[0])
if tlo is not None:
- #if 'App::Part' in sel[0].TypeId:
+ # if 'App::Part' in sel[0].TypeId:
explode_dwg.ui.hSlider_explode.setEnabled(True)
else:
explode_dwg.ui.hSlider_explode.setEnabled(False)
- #FreeCAD.Console.PrintMessage(document+"\n")
+ # FreeCAD.Console.PrintMessage(document+"\n")
# ...
+
+
###
+
###########################################
-class Ui_explode_dwg(object):
+class Ui_explode_dwg:
def setupUi(self, explode_dwg):
explode_dwg.setObjectName("explode_dwg")
explode_dwg.resize(306, 141)
explode_dwg.setMinimumSize(QtCore.QSize(91, 48))
explode_dwg.setLayoutDirection(QtCore.Qt.LeftToRight)
explode_dwg.setFeatures(QtGui.QDockWidget.AllDockWidgetFeatures)
- explode_dwg.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea|QtCore.Qt.RightDockWidgetArea)
+ explode_dwg.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea)
self.dockWidgetContents = QtGui.QWidget()
self.dockWidgetContents.setObjectName("dockWidgetContents")
self.mainGroup = QtGui.QGroupBox(self.dockWidgetContents)
@@ -177,9 +188,9 @@ def setupUi(self, explode_dwg):
self.retranslateUi(explode_dwg)
QtCore.QMetaObject.connectSlotsByName(explode_dwg)
- #def retranslateUi(self, explode_dwg):
- # explode_dwg.setWindowTitle(QtGui.QApplication.translate("explode_dwg", "Explode 3D PCB", None, QtGui.QApplication.UnicodeUTF8))
-################################################################################################
+ # def retranslateUi(self, explode_dwg):
+ # explode_dwg.setWindowTitle(QtGui.QApplication.translate("explode_dwg", "Explode 3D PCB", None, QtGui.QApplication.UnicodeUTF8))
+ ################################################################################################
explode_dwg.setWindowTitle("Explode 3D PCB")
self.pb_Close.clicked.connect(onCloseExp)
self.pb_Reset.clicked.connect(onReset)
@@ -187,204 +198,211 @@ def setupUi(self, explode_dwg):
self.hSlider_explode.setEnabled(False)
self.hSlider_explode.setToolTip("Explode PCB\nSelect the top container of a kicad PCB to exlode it")
icon = QtGui.QIcon()
- myicon=os.path.join( ksuWB_icons_path , 'closeSm.svg')
+ myicon = os.path.join(ksuWB_icons_path, "closeSm.svg")
icon.addPixmap(QtGui.QPixmap(myicon), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.pb_Close.setIcon(icon)
- #self.pb_Close.setIconSize(QtCore.QSize(btn_iconsize, btn_iconsize))
+ # self.pb_Close.setIconSize(QtCore.QSize(btn_iconsize, btn_iconsize))
self.pb_Close.setGeometry(QtCore.QRect(290, 72, btn_iconsize, btn_iconsize))
self.pb_Close.setText("")
icon = QtGui.QIcon()
- myicon=os.path.join( ksuWB_icons_path , 'Reset-to-Center.svg')
+ myicon = os.path.join(ksuWB_icons_path, "Reset-to-Center.svg")
icon.addPixmap(QtGui.QPixmap(myicon), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.pb_Reset.setIcon(icon)
- #self.pb_Reset.setIconSize(QtCore.QSize(btn_iconsize, btn_iconsize))
+ # self.pb_Reset.setIconSize(QtCore.QSize(btn_iconsize, btn_iconsize))
self.pb_Reset.setGeometry(QtCore.QRect(12, 72, btn_iconsize, btn_iconsize))
self.pb_Reset.setText("")
self.step_lineEdit.setText("0.5")
- #self.step_lineEdit.setGeometry(QtCore.QRect(12, 12, 12, 12))
- self.step_lineEdit.setMaximumSize(QtCore.QSize(btn_iconsize*2, btn_iconsize))
+ # self.step_lineEdit.setGeometry(QtCore.QRect(12, 12, 12, 12))
+ self.step_lineEdit.setMaximumSize(QtCore.QSize(btn_iconsize * 2, btn_iconsize))
self.label.setToolTip("incremental step (mm)")
def retranslateUi(self, explode_dwg):
pass
+
+
##############################################################
+
def explode_pcb(pos):
- doc = FreeCAD.ActiveDocument
docG = FreeCADGui.ActiveDocument
sc = 2.0
sel = FreeCADGui.Selection.getSelection()
if len(sel) == 1:
tlo = get_top_level(sel[0])
- #print (tlo.Label)
+ # print (tlo.Label)
if tlo is not None:
- #if 'App::Part' in sel[0].TypeId:
+ # if 'App::Part' in sel[0].TypeId:
for o in tlo.OutListRecursive:
- if 'Pcb' in o.Label:
- if o.TypeId == 'App::Part' or o.TypeId == 'App::LinkGroup':
+ if "Pcb" in o.Label:
+ if o.TypeId in {"App::Part", "App::LinkGroup"}:
for ob in o.OutList:
- if hasattr(ob,'Shape'):
- if (pos != 0):
- docG.getObject(ob.Name).Transparency=70
+ if hasattr(ob, "Shape"):
+ if pos != 0:
+ docG.getObject(ob.Name).Transparency = 70
else:
- docG.getObject(ob.Name).Transparency=0
- else:
- if hasattr(o,'Shape'):
- if (pos != 0):
- docG.getObject(o.Name).Transparency=70
- else:
- docG.getObject(o.Name).Transparency=0
- elif 'Top' in o.Label and 'TopV' not in o.Label:
- if hasattr(o,'Placement'):
- o.Placement.Base.z=pos
- elif 'Bot' in o.Label and 'BotV' not in o.Label:
- if hasattr(o,'Placement'):
- o.Placement.Base.z=-pos
- elif 'TopV' in o.Label:
- if hasattr(o,'Placement'):
- o.Placement.Base.z=pos*sc
- elif 'BotV' in o.Label:
- if hasattr(o,'Placement'):
- o.Placement.Base.z=-pos*sc
- elif 'topTracks' in o.Label or 'botTracks' in o.Label:
- if hasattr (o, 'Shape'):
- if (pos != 0):
- docG.getObject(o.Name).Transparency = 50
+ docG.getObject(ob.Name).Transparency = 0
+ elif hasattr(o, "Shape"):
+ if pos != 0:
+ docG.getObject(o.Name).Transparency = 70
else:
docG.getObject(o.Name).Transparency = 0
- elif 'topSilk' in o.Label or 'botSilk' in o.Label:
- if hasattr (o, 'Shape'):
- if (pos != 0):
- docG.getObject(o.Name).Transparency = 30
+ elif "Top" in o.Label and "TopV" not in o.Label:
+ if hasattr(o, "Placement"):
+ o.Placement.Base.z = pos
+ elif "Bot" in o.Label and "BotV" not in o.Label:
+ if hasattr(o, "Placement"):
+ o.Placement.Base.z = -pos
+ elif "TopV" in o.Label:
+ if hasattr(o, "Placement"):
+ o.Placement.Base.z = pos * sc
+ elif "BotV" in o.Label:
+ if hasattr(o, "Placement"):
+ o.Placement.Base.z = -pos * sc
+ elif "topTracks" in o.Label or "botTracks" in o.Label:
+ if hasattr(o, "Shape"):
+ if pos != 0:
+ docG.getObject(o.Name).Transparency = 50
else:
docG.getObject(o.Name).Transparency = 0
+ elif ("topSilk" in o.Label or "botSilk" in o.Label) and hasattr(o, "Shape"):
+ if pos != 0:
+ docG.getObject(o.Name).Transparency = 30
+ else:
+ docG.getObject(o.Name).Transparency = 0
return tlo
- #return None
+ return None
+ # return None
+
def SlideValueChange():
global toBeReset, explode_dwg
pos = explode_dwg.ui.hSlider_explode.sliderPosition() * float(explode_dwg.ui.step_lineEdit.text())
- #print('moving',pos)
+ # print('moving',pos)
toBeReset = explode_pcb(pos)
-#
+
+
def onReset():
global toBeReset, explode_dwg
- print ('Imploding')
+ print("Imploding")
sel = FreeCADGui.Selection.getSelection()
- if len (sel) == 0 and toBeReset is not None:
- try:
+ if len(sel) == 0 and toBeReset is not None:
+ with contextlib.suppress(BaseException):
FreeCADGui.Selection.addSelection(toBeReset)
- except:
- pass
explode_dwg.ui.hSlider_explode.setValue(0)
explode_pcb(0)
-#
+
+
def onCloseExp():
global s, explode_dwg
-
+
onReset()
"""closing dialog"""
- print('closing')
+ print("closing")
try:
FreeCADGui.Selection.removeObserver(s)
- print('observer removed')
+ print("observer removed")
except:
- print('observer not removed')
+ print("observer not removed")
explode_dwg.deleteLater()
+
+
#
##
+
def Exp_singleInstance():
- app = QtGui.QApplication #QtGui.qApp
+ app = QtGui.QApplication # QtGui.qApp
for i in app.topLevelWidgets():
- #i_say (str(i.objectName()))
+ # i_say (str(i.objectName()))
if i.objectName() == "ksuExplode":
- #i_say (str(i.objectName()))
- #i.close()
- #i.deleteLater()
- #i_say ('closed')
- return False
- t=FreeCADGui.getMainWindow()
- dw=t.findChildren(QtGui.QDockWidget)
- #say( str(dw) )
- for i in dw:
- #i_say (str(i.objectName()))
- if str(i.objectName()) == "ksuExplode": #"kicad StepUp 3D tools":
- #i_say (str(i.objectName())+' docked')
- #i.deleteLater()
+ # i_say (str(i.objectName()))
+ # i.close()
+ # i.deleteLater()
+ # i_say ('closed')
return False
- return True
+ t = FreeCADGui.getMainWindow()
+ dw = t.findChildren(QtGui.QDockWidget)
+ # say( str(dw) )
+ return all(str(i.objectName()) != "ksuExplode" for i in dw)
+
+
##
-def Exp_centerOnScreen ():
- '''centerOnScreen()
- Centers the window on the screen.'''
+
+def Exp_centerOnScreen():
+ """centerOnScreen()
+ Centers the window on the screen."""
# sayw(widg.width());sayw(widg.height())
# sayw(widg.pos().x());sayw(widg.pos().y())
if hasattr(QtGui.QGuiApplication, "primaryScreen"):
resolution = QtGui.QGuiApplication.primaryScreen().availableGeometry()
else:
resolution = QtGui.QDesktopWidget().screenGeometry()
- xp=(resolution.width() / 2) - sizeX/2 # - (KSUWidget.frameSize().width() / 2)
- yp=(resolution.height() / 2) - sizeY/2 # - (KSUWidget.frameSize().height() / 2))
+ xp = (resolution.width() / 2) - sizeX / 2 # - (KSUWidget.frameSize().width() / 2)
+ yp = (resolution.height() / 2) - sizeY / 2 # - (KSUWidget.frameSize().height() / 2))
# xp=widg.pos().x()-sizeXMax/2;yp=widg.pos().y()#+sizeY/2
explode_dwg.setGeometry(xp, yp, sizeX, sizeY)
+
+
##
+
def Exp_putOnTopRightCorner():
resolution = QtGui.QDesktopWidget().screenGeometry()
margin = 80
- xp=(resolution.width()) - sizeX -margin/5 # - (KSUWidget.frameSize().width() / 2)
- yp=(resolution.height()) - sizeY - margin # - (KSUWidget.frameSize().height() / 2))
+ xp = (resolution.width()) - sizeX - margin / 5 # - (KSUWidget.frameSize().width() / 2)
+ # yp = (resolution.height()) - sizeY - margin # - (KSUWidget.frameSize().height() / 2))
# xp=widg.pos().x()-sizeXMax/2;yp=widg.pos().y()#+sizeY/2
explode_dwg.setGeometry(xp, margin, sizeX, sizeY)
- #self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
- #self.show()
+ # self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
+ # self.show()
+
def runExplodeGui():
global explode_dwg
- doc=FreeCAD.ActiveDocument
-
+
if Exp_singleInstance():
global s
-
+
explode_dwg = QtGui.QDockWidget()
explode_dwg.ui = Ui_explode_dwg()
explode_dwg.ui.setupUi(explode_dwg)
explode_dwg.setObjectName("ksuExplode")
explode_dwg.raise_()
- explode_dwg.setFeatures( QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable ) # | QtGui.QDockWidget.DockWidgetClosable )
-
- #RHDockWidget.destroyed.connect(onDestroy)
- #explode_dwg.visibilityChanged.connect(onClickClose)
-
- ExpMw = FreeCADGui.getMainWindow() # PySide # the active qt window, = the freecad window since we are inside it
- ExpMw.addDockWidget(QtCore.Qt.RightDockWidgetArea,explode_dwg)
- explode_dwg.setFloating(True) #undock
- #RHDockWidget.resize(sizeX,sizeY)
- #Exp_centerOnScreen()
+ explode_dwg.setFeatures(
+ QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable,
+ ) # | QtGui.QDockWidget.DockWidgetClosable )
+
+ # RHDockWidget.destroyed.connect(onDestroy)
+ # explode_dwg.visibilityChanged.connect(onClickClose)
+
+ ExpMw = FreeCADGui.getMainWindow() # PySide # the active qt window, = the freecad window since we are inside it
+ ExpMw.addDockWidget(QtCore.Qt.RightDockWidgetArea, explode_dwg)
+ explode_dwg.setFloating(True) # undock
+ # RHDockWidget.resize(sizeX,sizeY)
+ # Exp_centerOnScreen()
Exp_putOnTopRightCorner()
- s=expSelectionObserver()
+ s = expSelectionObserver()
FreeCADGui.Selection.addObserver(s)
-
+
onReset()
- #explode_dwg.ui.Version.setText(__version__)
-
- #else:
- #raising up
+ # explode_dwg.ui.Version.setText(__version__)
+
+ # else:
+ # raising up
explode_dwg.activateWindow()
explode_dwg.raise_()
sel = FreeCADGui.Selection.getSelection()
- if len (sel)== 1:
+ if len(sel) == 1:
tlo = get_top_level(sel[0])
if tlo is not None:
- #if 'App::Part' in sel[0].TypeId:
+ # if 'App::Part' in sel[0].TypeId:
explode_dwg.ui.hSlider_explode.setEnabled(True)
else:
explode_dwg.ui.hSlider_explode.setEnabled(False)
-#if __name__ == "__main__":
+# if __name__ == "__main__":
# import sys
# app = QtGui.QApplication(sys.argv)
# explode_dwg = QtGui.QDockWidget()
@@ -392,5 +410,3 @@ def runExplodeGui():
# ui.setupUi(explode_dwg)
# explode_dwg.show()
# sys.exit(app.exec_())
-
-
diff --git a/fps.py b/fps.py
index 0508a38..fffcfc1 100644
--- a/fps.py
+++ b/fps.py
@@ -1,63 +1,74 @@
#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#****************************************************************************
+# ****************************************************************************
global fps_version
-fps_version = '1.1.3'
+fps_version = "1.1.3"
-dvp=False #True
+dvp = False # True
if dvp:
- import fps; import importlib; importlib.reload(fps)
+ import importlib
-#import kicad_parser; import importlib; importlib.reload(kicad_parser)
+ import fps
+
+ importlib.reload(fps)
+
+# import kicad_parser; import importlib; importlib.reload(kicad_parser)
import time
+
import PySide
-from PySide import QtGui, QtCore
+from PySide import QtGui
+
QtWidgets = QtGui
-import sys,os
-import FreeCAD, FreeCADGui
-import Draft, Part
+import os
-#import fcad_pcb
-#from fcad_pcb import kicad
+import FreeCAD
+import FreeCADGui
+import Part
-import fcad_parser
+# import fcad_pcb
+# from fcad_pcb import kicad
import kicad_parser
from kicad_parser import KicadPCB, make_fp_poly
-import math
-from math import radians
-
consolePrint = FreeCAD.Console.PrintMessage
-consolePrint('fp loader v'+fps_version+'\n')
+consolePrint("fp loader v" + fps_version + "\n")
global start_time, last_pcb_path, min_drill_size, deltaz
-#pcbThickness=1.6
-deltaz = 0.01 #10 micron
+# pcbThickness=1.6
+deltaz = 0.01 # 10 micron
annotation_fontsize = 12.0
+
def getFCversion():
- FC_majorV=int(float(FreeCAD.Version()[0]))
- FC_minorV=int(float(FreeCAD.Version()[1]))
+ FC_majorV = int(float(FreeCAD.Version()[0]))
+ FC_minorV = int(float(FreeCAD.Version()[1]))
try:
- FC_git_Nbr=int (float(FreeCAD.Version()[2].strip(" (Git)").split(' ')[0])) #+int(FreeCAD.Version()[2].strip(" (Git)").split(' ')[1])
+ FC_git_Nbr = int(
+ float(FreeCAD.Version()[2].strip(" (Git)").split(" ")[0]),
+ ) # +int(FreeCAD.Version()[2].strip(" (Git)").split(' ')[1])
except:
- FC_git_Nbr=0
- return FC_majorV,FC_minorV,FC_git_Nbr
+ FC_git_Nbr = 0
+ return FC_majorV, FC_minorV, FC_git_Nbr
+
+
+FC_majorV, FC_minorV, FC_git_Nbr = getFCversion()
+FreeCAD.Console.PrintWarning("FC Version " + str(FC_majorV) + str(FC_minorV) + "-" + str(FC_git_Nbr) + "\n")
-FC_majorV,FC_minorV,FC_git_Nbr=getFCversion()
-FreeCAD.Console.PrintWarning('FC Version '+str(FC_majorV)+str(FC_minorV)+"-"+str(FC_git_Nbr)+'\n')
-current_milli_time = lambda: int(round(time.time() * 1000))
+def current_milli_time():
+ return round(time.time() * 1000)
+
def say_time():
end_milli_time = current_milli_time()
- running_time=(end_milli_time-start_time)/1000
- msg="running time: "+str(running_time)+"sec"
+ running_time = (end_milli_time - start_time) / 1000
+ msg = "running time: " + str(running_time) + "sec"
print(msg)
+
+
###
-py2=False
+py2 = False
try: ## maui py3
unicode = unicode
except NameError:
@@ -65,98 +76,101 @@ def say_time():
str = str
unicode = str
bytes = bytes
- basestring = (str,bytes)
+ basestring = (str, bytes)
else:
# 'unicode' exists, must be Python 2
str = str
unicode = unicode
bytes = str
basestring = basestring
- py2=True
+ py2 = True
+
def reload_lib(lib):
- if (sys.version_info > (3, 0)):
- import importlib
- importlib.reload(lib)
- else:
- reload (lib)
+ import importlib
+
+ importlib.reload(lib)
+
def recompute_active_object():
try:
FreeCAD.ActiveDocument.ActiveObject.recompute(True)
except:
FreeCAD.ActiveDocument.ActiveObject.recompute()
-##
-def makeAnno (name,bp,txt,afs):
-
- doc=FreeCAD.ActiveDocument
- anno = doc.addObject("App::AnnotationLabel",name)
+
+##
+
+
+def makeAnno(name, bp, txt, afs):
+
+ doc = FreeCAD.ActiveDocument
+ anno = doc.addObject("App::AnnotationLabel", name)
anno.BasePosition = bp
anno.LabelText = txt
- anno.ViewObject.FontSize=afs
+ anno.ViewObject.FontSize = afs
return anno
-#
+
def crc_gen_t(data):
import binascii
import re
-
- #data=u'Würfel'
- content=re.sub(r'[^\x00-\x7F]+','_', data)
- #make_unicode(hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
- #hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:].encode('utf-8')
- #print(data +u'_'+ hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
- return u'_'+ make_unicode_t(hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
+
+ # data=u'Würfel'
+ content = re.sub(r"[^\x00-\x7F]+", "_", data)
+ # make_unicode(hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
+ # hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:].encode('utf-8')
+ # print(data +u'_'+ hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
+ return "_" + make_unicode_t(hex(binascii.crc_hqx(content.encode("utf-8"), 0x0000))[2:])
+
+
##
+
def make_unicode_t(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.decode('utf-8')
- return input
- else: #py2
- if type(input) != unicode:
- input = input.decode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.decode("utf-8")
+ if type(input) != unicode:
+ return input.decode("utf-8")
+ return input
+
def mkColor(*color):
- if len(color)==1:
- if isinstance(color[0],basestring):
- if color[0].startswith('#'):
- #color = color[0].replace('#','0x')
- #color = int(color,0)
- #print (color)
- #r = float((color>>24)&0xFF)
- #g = float((color>>16)&0xFF)
- #b = float((color>>8)&0xFF)
- color = color[0] #[1:]
- #print(color[1:3])
- r = int((color[1:3]), 16) #/255
- g = int((color[3:5]), 16) #/255
- b = int((color[5:7]), 16) #/255
- #print(r,g,b);stop
- #print(r,g,b)
- #stop
+ if len(color) == 1:
+ if isinstance(color[0], basestring):
+ if color[0].startswith("#"):
+ # color = color[0].replace('#','0x')
+ # color = int(color,0)
+ # print (color)
+ # r = float((color>>24)&0xFF)
+ # g = float((color>>16)&0xFF)
+ # b = float((color>>8)&0xFF)
+ color = color[0] # [1:]
+ # print(color[1:3])
+ r = int((color[1:3]), 16) # /255
+ g = int((color[3:5]), 16) # /255
+ b = int((color[5:7]), 16) # /255
+ # print(r,g,b);stop
+ # print(r,g,b)
+ # stop
else:
- color = int(color[0],0)
- r = float((color>>24)&0xFF)
- g = float((color>>16)&0xFF)
- b = float((color>>8)&0xFF)
+ color = int(color[0], 0)
+ r = float((color >> 24) & 0xFF)
+ g = float((color >> 16) & 0xFF)
+ b = float((color >> 8) & 0xFF)
else:
color = color[0]
- r = float((color>>24)&0xFF)
- g = float((color>>16)&0xFF)
- b = float((color>>8)&0xFF)
+ r = float((color >> 24) & 0xFF)
+ g = float((color >> 16) & 0xFF)
+ b = float((color >> 8) & 0xFF)
else:
- r,g,b = color
- return (r/255.0,g/255.0,b/255.0)
+ r, g, b = color
+ return (r / 255.0, g / 255.0, b / 255.0)
+
+
##
-#colors = {
+# colors = {
# 'board':makeColor("0x3A6629"),
# 'pad':{0:makeColor(219,188,126)},
# 'zone':{0:makeColor(200,117,51)},
@@ -164,39 +178,39 @@ def mkColor(*color):
# 'copper':{0:makeColor(200,117,51)},
# }
-def extrude_holes (holes,w):
- FreeCAD.ActiveDocument.addObject("Part::Extrusion","Extrude_drills")
- extrude_d_name=FreeCAD.ActiveDocument.ActiveObject.Name
+def extrude_holes(holes, w):
+
+ FreeCAD.ActiveDocument.addObject("Part::Extrusion", "Extrude_drills")
+ extrude_d_name = FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.getObject(extrude_d_name).Base = FreeCAD.ActiveDocument.getObject(holes.Name)
- FreeCAD.ActiveDocument.getObject(extrude_d_name).Dir = (0,0,w)
- FreeCAD.ActiveDocument.getObject(extrude_d_name).Solid = (True)
- FreeCAD.ActiveDocument.getObject(extrude_d_name).TaperAngle = (0)
+ FreeCAD.ActiveDocument.getObject(extrude_d_name).Dir = (0, 0, w)
+ FreeCAD.ActiveDocument.getObject(extrude_d_name).Solid = True
+ FreeCAD.ActiveDocument.getObject(extrude_d_name).TaperAngle = 0
FreeCAD.ActiveDocument.getObject(extrude_d_name).Symmetric = True
FreeCADGui.ActiveDocument.getObject(holes.Name).Visibility = False
- FreeCAD.ActiveDocument.getObject(extrude_d_name).Label = 'solid_drills'
- extrude_drill_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.getObject(extrude_d_name).Label = "solid_drills"
recompute_active_object()
FreeCADGui.ActiveDocument.getObject(holes.Name).Visibility = False
-#
-def cut_fuzzy(base,tool,ftol):
+
+def cut_fuzzy(base, tool, ftol):
Part.show(base.Shape.cut(tool.Shape, ftol))
-
-#
-def cut_out_tracks (pcbsk,tracks,tname_sfx):
-
+
+def cut_out_tracks(pcbsk, tracks, tname_sfx):
+
# import tracks; import importlib;importlib.reload(tracks)
import random
+
temp_tobedeleted = []
removing_temp_objs = False
- Extrude_Name = 'Extrude' + str(random.randrange(1,100))
- FreeCAD.ActiveDocument.addObject('Part::Extrusion', Extrude_Name)
+ Extrude_Name = "Extrude" + str(random.randrange(1, 100))
+ FreeCAD.ActiveDocument.addObject("Part::Extrusion", Extrude_Name)
extrude = FreeCAD.ActiveDocument.ActiveObject
- #f = FreeCAD.ActiveDocument.getObject('Extrude')
- print (pcbsk.Name)
+ # f = FreeCAD.ActiveDocument.getObject('Extrude')
+ print(pcbsk.Name)
extrude.Base = pcbsk
extrude.DirMode = "Custom"
extrude.Dir = (0.000, 0.000, 1.000)
@@ -208,35 +222,54 @@ def cut_out_tracks (pcbsk,tracks,tname_sfx):
extrude.Symmetric = True
extrude.TaperAngle = 0.000000000000000
extrude.TaperAngleRev = 0.000000000000000
- extrude.ViewObject.ShapeColor=getattr(pcbsk.getLinkedObject(True).ViewObject,'ShapeColor',extrude.ViewObject.ShapeColor)
- extrude.ViewObject.LineColor=getattr(pcbsk.getLinkedObject(True).ViewObject,'LineColor',extrude.ViewObject.LineColor)
- extrude.ViewObject.PointColor=getattr(pcbsk.getLinkedObject(True).ViewObject,'PointColor',extrude.ViewObject.PointColor)
+ extrude.ViewObject.ShapeColor = getattr(
+ pcbsk.getLinkedObject(True).ViewObject,
+ "ShapeColor",
+ extrude.ViewObject.ShapeColor,
+ )
+ extrude.ViewObject.LineColor = getattr(
+ pcbsk.getLinkedObject(True).ViewObject,
+ "LineColor",
+ extrude.ViewObject.LineColor,
+ )
+ extrude.ViewObject.PointColor = getattr(
+ pcbsk.getLinkedObject(True).ViewObject,
+ "PointColor",
+ extrude.ViewObject.PointColor,
+ )
pcbsk.Visibility = False
FreeCAD.ActiveDocument.recompute()
- Common_Top_Name = "Common_Top"+ str(random.randrange(1,100))
- FreeCAD.ActiveDocument.addObject("Part::MultiCommon",Common_Top_Name)
+ Common_Top_Name = "Common_Top" + str(random.randrange(1, 100))
+ FreeCAD.ActiveDocument.addObject("Part::MultiCommon", Common_Top_Name)
Common_Top = FreeCAD.ActiveDocument.ActiveObject
- Common_Top.Shapes = [tracks,extrude,]
- FreeCADGui.ActiveDocument.getObject(tracks.Name).Visibility=False
- FreeCADGui.ActiveDocument.getObject(extrude.Name).Visibility=False
+ Common_Top.Shapes = [
+ tracks,
+ extrude,
+ ]
+ FreeCADGui.ActiveDocument.getObject(tracks.Name).Visibility = False
+ FreeCADGui.ActiveDocument.getObject(extrude.Name).Visibility = False
FreeCAD.ActiveDocument.recompute()
-
+
# placing inside the container
- if len (FreeCAD.ActiveDocument.getObjectsByLabel('Board_Geoms'+tname_sfx)) > 0:
+ if len(FreeCAD.ActiveDocument.getObjectsByLabel("Board_Geoms" + tname_sfx)) > 0:
# extrude.adjustRelativeLinks(FreeCAD.ActiveDocument.getObject('Board_Geoms'+tname_sfx))
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+tname_sfx).addObject(extrude)
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + tname_sfx).addObject(extrude)
# simple copy
- FreeCAD.ActiveDocument.addObject('Part::Feature',tracks.Label+'_').Shape=FreeCAD.ActiveDocument.getObject(Common_Top.Name).Shape
- tracks_ct = FreeCAD.ActiveDocument.ActiveObject
- tracks_ctV = FreeCADGui.ActiveDocument.ActiveObject
- new_label=tracks.Label +'_cut'
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(Common_Top.Name).ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(Common_Top.Name).ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(Common_Top.Name).LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(Common_Top.Name).PointColor
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(Common_Top.Name).DiffuseColor
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(Common_Top.Name).Transparency
- FreeCAD.ActiveDocument.ActiveObject.Label=new_label
+ FreeCAD.ActiveDocument.addObject("Part::Feature", tracks.Label + "_").Shape = FreeCAD.ActiveDocument.getObject(
+ Common_Top.Name,
+ ).Shape
+ new_label = tracks.Label + "_cut"
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(Common_Top.Name).ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(Common_Top.Name).ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(Common_Top.Name).LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(Common_Top.Name).PointColor
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject(
+ Common_Top.Name,
+ ).DiffuseColor
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject(
+ Common_Top.Name,
+ ).Transparency
+ FreeCAD.ActiveDocument.ActiveObject.Label = new_label
tracks_ct_Name = FreeCAD.ActiveDocument.ActiveObject.Name
if removing_temp_objs:
FreeCAD.ActiveDocument.removeObject(Common_Top.Name)
@@ -244,37 +277,39 @@ def cut_out_tracks (pcbsk,tracks,tname_sfx):
FreeCAD.ActiveDocument.removeObject(extrude.Name)
else:
doc = FreeCAD.ActiveDocument
- #temp_tobedeleted.append([doc.getObject(Common_Top.Name),doc.getObject(tracks.Name),doc.getObject(extrude.Name)])
+ # temp_tobedeleted.append([doc.getObject(Common_Top.Name),doc.getObject(tracks.Name),doc.getObject(extrude.Name)])
temp_tobedeleted.append(doc.getObject(Common_Top.Name))
temp_tobedeleted.append(doc.getObject(tracks.Name))
temp_tobedeleted.append(doc.getObject(extrude.Name))
FreeCAD.ActiveDocument.getObject(tracks_ct_Name).Label = new_label
FreeCAD.ActiveDocument.recompute()
-
+
return tracks_ct_Name, temp_tobedeleted
+
+
##
-def simple_cpy (obj,lbl):
- copy = FreeCAD.ActiveDocument.addObject('Part::Feature',obj.Name)
+def simple_cpy(obj, lbl):
+ copy = FreeCAD.ActiveDocument.addObject("Part::Feature", obj.Name)
copy.Label = lbl
copy.Shape = obj.Shape
- copy.ViewObject.ShapeColor = obj.ViewObject.ShapeColor
- copy.ViewObject.LineColor = obj.ViewObject.LineColor
- copy.ViewObject.PointColor = obj.ViewObject.PointColor
+ copy.ViewObject.ShapeColor = obj.ViewObject.ShapeColor
+ copy.ViewObject.LineColor = obj.ViewObject.LineColor
+ copy.ViewObject.PointColor = obj.ViewObject.PointColor
copy.ViewObject.DiffuseColor = obj.ViewObject.DiffuseColor
return copy
+
+
#
-#def rmv_obj(o):
+# def rmv_obj(o):
# FreeCADGui.Selection.clearSelection()
# FreeCADGui.Selection.addSelection(doc.getObject(pads.Name))
# removesubtree(FreeCADGui.Selection.getSelection())
#
-from kicadStepUptools import removesubtree, cfg_read_all
-from kicadStepUptools import make_unicode, make_string
-import fcad_parser
-from fcad_parser import KicadPCB,SexpList
+from fcad_parser import KicadPCB # noqa: F811
+from kicadStepUptools import make_string, make_unicode, removesubtree
-start_f="""(kicad_pcb (version 20211014) (generator pcbnew)
+start_f = """(kicad_pcb (version 20211014) (generator pcbnew)
(general
(thickness 1.6)
@@ -314,224 +349,238 @@ def simple_cpy (obj,lbl):
)
"""
-end_f="""
+end_f = """
)"""
-#filename="C:/Cad/Progetti_K/ksu-test/pic_smart_switch.kicad_pcb"
-#filename="C:/Cad/Progetti_K/eth-32gpio/eth-32gpio.kicad_pcb"
-def addfootprint(fname = None):
+
+# filename="C:/Cad/Progetti_K/ksu-test/pic_smart_switch.kicad_pcb"
+# filename="C:/Cad/Progetti_K/eth-32gpio/eth-32gpio.kicad_pcb"
+def addfootprint(fname=None):
global start_time, last_pcb_path, min_drill_size
global tracks_version
global start_f, end_f, deltaz
- import sys
- import kicad_parser
- FreeCAD.Console.PrintMessage('kicad_parser_version '+kicad_parser.__kicad_parser_version__+'\n') # maui
+ FreeCAD.Console.PrintMessage("kicad_parser_version " + kicad_parser.__kicad_parser_version__ + "\n") # maui
# cfg_read_all() it doesn't work through different files
# print (min_drill_size)
-
- FreeCAD.Console.PrintMessage('footprints version: '+fps_version+'\n')
-
- Filter=""
+
+ FreeCAD.Console.PrintMessage("footprints version: " + fps_version + "\n")
+
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
if fname is None:
last_pcb_path = pg.GetString("last_pcb_path")
- if len (last_pcb_path) == 0:
- last_pcb_path = ""
+ if len(last_pcb_path) == 0:
+ last_pcb_path = ""
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- #print('native_dlg',prefs_.GetBool('native_dlg'))
- if not(prefs_.GetBool('not_native_dlg')):
- fname, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open File...",
- make_unicode(last_pcb_path), "*.kicad_mod")
+ # print('native_dlg',prefs_.GetBool('native_dlg'))
+ if not (prefs_.GetBool("not_native_dlg")):
+ fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open File...",
+ make_unicode(last_pcb_path),
+ "*.kicad_mod",
+ )
else:
- fname, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open File...",
- make_unicode(last_pcb_path), "*.kicad_mod",options=QtWidgets.QFileDialog.DontUseNativeDialog)
- path, name = os.path.split(fname)
- #filename=os.path.splitext(name)[0]
+ fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open File...",
+ make_unicode(last_pcb_path),
+ "*.kicad_mod",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
+ _path, _name = os.path.split(fname)
+ # filename=os.path.splitext(name)[0]
filename = fname
- #importDXF.open(os.path.join(dirname,filename))
+ # importDXF.open(os.path.join(dirname,filename))
if len(fname) > 0:
- start_time=current_milli_time()
- last_pcb_path=os.path.dirname(fname)
- path, ftname = os.path.split(fname)
- ftname=os.path.splitext(ftname)[0]
- ftname_sfx=crc_gen_t(make_unicode_t(ftname))
+ start_time = current_milli_time()
+ last_pcb_path = os.path.dirname(fname)
+ _path, ftname = os.path.split(fname)
+ ftname = os.path.splitext(ftname)[0]
+ crc_gen_t(make_unicode_t(ftname))
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- pg.SetString("last_pcb_path", make_string(last_pcb_path)) # py3 .decode("utf-8")
+ pg.SetString("last_pcb_path", make_string(last_pcb_path)) # py3 .decode("utf-8")
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- pcb_color_pos = prefs.GetInt('pcb_color')
- #pcb_color_values = [light_green,blue,red,purple,darkgreen,darkblue,lightblue,yellow,black,white]
- assign_col=['#41c382','#2474cf','#ff4000','#9a1a85','#3c7f5d','#426091','#005fff','#fff956','#4d4d4d','#f0f0f0']
- #print(pcb_color_pos)
+ pcb_color_pos = prefs.GetInt("pcb_color")
+ # pcb_color_values = [light_green,blue,red,purple,darkgreen,darkblue,lightblue,yellow,black,white]
+ assign_col = [
+ "#41c382",
+ "#2474cf",
+ "#ff4000",
+ "#9a1a85",
+ "#3c7f5d",
+ "#426091",
+ "#005fff",
+ "#fff956",
+ "#4d4d4d",
+ "#f0f0f0",
+ ]
+ # print(pcb_color_pos)
pcb_transparency = 80
- pcb_col = (assign_col[pcb_color_pos])
- if pcb_color_pos == 9:
- slk_col = '#2d2d2d'
- else:
- slk_col = '#f8f8f0'
- pads_color = (0.81,0.71,0.23) #(0.85,0.53,0.10)
+ pcb_col = assign_col[pcb_color_pos]
+ pads_color = (0.81, 0.71, 0.23) # (0.85,0.53,0.10)
pads_transparency = 60
- nettie_color = (1.0,0.33,0.0)
+ nettie_color = (1.0, 0.33, 0.0)
nettie_transparency = 50
- tbassembled=[]
- # import kicad_parser
+ tbassembled = []
+ # import kicad_parser
# pcb = kicad_parser.KicadFcad(filename)
del_file = False
-
- consolePrint(filename+'\n')
- fn=os.path.splitext(os.path.basename(filename))[0]
-
- if filename.endswith('kicad_mod'):
- with open(filename , 'r', encoding="utf-8", errors="ignore") as f:
- lines = f.readlines() # readlines creates a list of the lines
- #lines = start_f+lines+end_f
+
+ consolePrint(filename + "\n")
+ fn = os.path.splitext(os.path.basename(filename))[0]
+
+ if filename.endswith("kicad_mod"):
+ with open(filename, encoding="utf-8", errors="ignore") as f:
+ lines = f.readlines() # readlines creates a list of the lines
+ # lines = start_f+lines+end_f
import tempfile
- tmp = tempfile.NamedTemporaryFile(delete=False,suffix='.kicad_pcb')
- with tmp as f:
- #with open(tmp.name, 'w') as f:
+
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".kicad_pcb") as f:
+ # with open(tmp.name, 'w') as f:
for l in start_f:
- f.write(l.encode(encoding='UTF-8'))
+ f.write(l.encode(encoding="UTF-8"))
for l in lines:
- f.write(l.encode(encoding='UTF-8'))
+ f.write(l.encode(encoding="UTF-8"))
for l in end_f:
- f.write(l.encode(encoding='UTF-8'))
+ f.write(l.encode(encoding="UTF-8"))
filename = tmp.name
del_file = True
- #print(filename)
-
+ # print(filename)
+
_pcb = KicadPCB.load(filename)
- pcb = kicad_parser.KicadFcad(filename,via_skip_hole=False,via_bound=0)
+ pcb = kicad_parser.KicadFcad(filename, via_skip_hole=False, via_bound=0)
if del_file:
os.remove(filename)
- consolePrint('file removed\n')
- doc=FreeCAD.ActiveDocument
+ consolePrint("file removed\n")
+ doc = FreeCAD.ActiveDocument
if doc is None:
- doc=FreeCAD.newDocument()
+ doc = FreeCAD.newDocument()
doc.Label = fn
- ini_objs=doc.Objects
FreeCADGui.ActiveDocument.ActiveView.viewTop()
- doc.openTransaction('addFp')
+ doc.openTransaction("addFp")
pcbThickness = float(_pcb.general.thickness)
fp_name = fn
- ar=0
- rx=0; ry=0; rz=0
+ rx = 0
+ ry = 0
+ rz = 0
rotations = []
- for i,m in enumerate(_pcb.module):
- if hasattr(m, 'model'):
+ for i, m in enumerate(_pcb.module):
+ if hasattr(m, "model"):
try:
- for j,md in enumerate(m.model):
- rx=md.rotate.xyz[0]
- ry=md.rotate.xyz[1]
- rz=md.rotate.xyz[2]
- ar=md.rotate.xyz[2]
- if rx!=0 or ry!=0 or rz != 0:
+ for j, md in enumerate(m.model):
+ rx = md.rotate.xyz[0]
+ ry = md.rotate.xyz[1]
+ rz = md.rotate.xyz[2]
+ md.rotate.xyz[2]
+ if rx != 0 or ry != 0 or rz != 0:
# rotations.append('model3D('+str(j)+')'+str('('+str(rx)+', '+str(ry)+', '+str(rz)+')\n'))
# rotations.append((md[0]+" model3D("+str(j)+") "+str((rx,ry,rz))))
- rotations.append((str((rx,ry,rz))+" "+md[0]))
- #print(rotations)
+ rotations.append(str((rx, ry, rz)) + " " + md[0])
+ # print(rotations)
except:
pass
# print(m.fp_text[1][0],m.fp_text[1][1])
- if hasattr(m, 'fp_text'):
+ if hasattr(m, "fp_text"):
for t in m.fp_text:
- #print(t[0],' ',t[1])
- if t[0] == 'value':
+ # print(t[0],' ',t[1])
+ if t[0] == "value":
fp_name = t[1]
- if hasattr(m, 'property'): #kv8 fp
+ if hasattr(m, "property"): # kv8 fp
for t in m.property:
- #print(t[0],' ',t[1])
- if t[0].lower == 'value':
+ # print(t[0],' ',t[1])
+ if t[0].lower == "value":
fp_name = t[1]
- if hasattr(m, 'zone'):
+ if hasattr(m, "zone"):
# print(m.zone)
- zones=[]
- #print(m.zone, len(m.zone))
- #print(SexpList(m.zone))
- #zl=SexpList(m.zone)
- #z0=zl[0]
- #Part.show(make_fp_poly(z0.polygon))
+ zones = []
+ # print(m.zone, len(m.zone))
+ # print(SexpList(m.zone))
+ # zl=SexpList(m.zone)
+ # z0=zl[0]
+ # Part.show(make_fp_poly(z0.polygon))
## print(zl.layer)
- #zl = m.zone
- #z0=zl[0]
- #print(z0.polygon)
- #Part.show(make_fp_poly(z0.polygon))
- #zl=SexpList(m.zone)
- #print(zl)
+ # zl = m.zone
+ # z0=zl[0]
+ # print(z0.polygon)
+ # Part.show(make_fp_poly(z0.polygon))
+ # zl=SexpList(m.zone)
+ # print(zl)
# print(m.zone)
- #if hasattr(m.zone, 'polygon'):
- for z in (m.zone):
+ # if hasattr(m.zone, 'polygon'):
+ for z in m.zone:
# print(z) #,SexpList(z))
# print(z.layer)
# print(z.keepout)
# print(z.polygon.pts)
- if hasattr(z,'keepout'):
- pg=make_fp_poly(z.polygon)
+ if hasattr(z, "keepout"):
+ pg = make_fp_poly(z.polygon)
zones.append(pg)
if len(zones) > 0:
- consolePrint('making keepout zones\n')
+ consolePrint("making keepout zones\n")
Part.show(Part.makeCompound(zones))
zn = doc.ActiveObject
- zn.Label = 'keepout-Zones'
- zn.ViewObject.DrawStyle = u"Dashed"
- zn.ViewObject.LineColor = (255.0,0.0,127.0)
+ zn.Label = "keepout-Zones"
+ zn.ViewObject.DrawStyle = "Dashed"
+ zn.ViewObject.LineColor = (255.0, 0.0, 127.0)
import Draft
+
# if ar!=0:
# zn.Placement.Rotation.Angle = radians(ar)
- zone_keepout = Draft.makeSketch(zn,autoconstraints=True)
- zone_keepout.Label = 'keepout-Zones_'
- zone_keepout.ViewObject.DrawStyle = u"Dashed"
- zone_keepout.ViewObject.LineColor = (255.0,0.0,127.0)
+ zone_keepout = Draft.makeSketch(zn, autoconstraints=True)
+ zone_keepout.Label = "keepout-Zones_"
+ zone_keepout.ViewObject.DrawStyle = "Dashed"
+ zone_keepout.ViewObject.LineColor = (255.0, 0.0, 127.0)
doc.removeObject(zn.Name)
tbassembled.append(zone_keepout)
- #stop
- #from kicad_parser import KicadFcad
- #from kicad_parser import makePads
+ # stop
+ # from kicad_parser import KicadFcad
+ # from kicad_parser import makePads
# import kicad_pads_parser
# for m in _pcb.module:
# for p in m.pad:
# print (p)
# # kicad_pads_parser.makePads(p,shape_type='solid',thickness=0.01,holes=True,fit_arcs=True)
# # KicadFcad.makePads(shape_type='solid',thickness=0.01,holes=True,fit_arcs=True)
-
+
# if len(rotations) >0:
# print('rotations',rotations)
# makeAnno (name,bp,txt,afs):
# anno = makeAnno('3Dmodel rotation(s)',FreeCAD.Vector(0,0,0),'3Dmodel rotations\n'+str(rotations),annotation_fontsize)
- #print(ar)
+ # print(ar)
# pcb = kicad.KicadFcad(filename,via_skip_hole=False,via_bound=0)
-
- consolePrint('making holes\n')
+
+ consolePrint("making holes\n")
Holes_Compound = None
- holesT=pcb.makeHoles(shape_type='solid',oval=True)
- if hasattr (holesT,'Name'):
+ holesT = pcb.makeHoles(shape_type="solid", oval=True)
+ if hasattr(holesT, "Name"):
holesT.ViewObject.Transparency = 70
- holesT.Placement.Base.z-=pcbThickness-deltaz
+ holesT.Placement.Base.z -= pcbThickness - deltaz
# if ar!=0:
# holesT.Placement.Rotation.Angle = radians(ar)
hole_ws = holesT.OutList[0].OutList[0].Shape
- wires=hole_ws.Wires
- anr=[]
- tbd=[]
- i=0
+ wires = hole_ws.Wires
+ anr = []
+ tbd = []
+ i = 0
for w in wires:
Part.show(w)
ia = doc.ActiveObject
- doc.addObject("Part::Offset2D","Offset2D")
- o2d=doc.ActiveObject
- o2d.Source = ia #doc.getObject(ia.Name)
+ doc.addObject("Part::Offset2D", "Offset2D")
+ o2d = doc.ActiveObject
+ o2d.Source = ia # doc.getObject(ia.Name)
o2d.Value = 0.01
doc.recompute()
tbd.append(o2d)
- dw=[o2d.Shape.Wires,ia.Shape.Wires]
# s = Part.makeCompound([o2d.Shape,ia.Shape]).extrude(FreeCAD.Vector(0.0, 0.0, -pcbThickness))
- s = Part.makeCompound([o2d.Shape,ia.Shape])
+ s = Part.makeCompound([o2d.Shape, ia.Shape])
Part.show(s)
s = doc.ActiveObject
- doc.addObject('Part::Extrusion', 'drl_ann')
+ doc.addObject("Part::Extrusion", "drl_ann")
extrude = doc.ActiveObject
- #f = FreeCAD.ActiveDocument.getObject('Extrude')
+ # f = FreeCAD.ActiveDocument.getObject('Extrude')
extrude.Base = s
extrude.DirMode = "Custom"
extrude.Dir = (0.000, 0.000, 1.000)
@@ -543,284 +592,290 @@ def addfootprint(fname = None):
extrude.Symmetric = False
doc.recompute()
tbd.append(extrude)
- doc.addObject('Part::Feature','anr_').Shape=extrude.Shape
- nanr=doc.ActiveObject
- nanr.Label='drill_'+'{0:0{1}}'.format(i, 3)
+ doc.addObject("Part::Feature", "anr_").Shape = extrude.Shape
+ nanr = doc.ActiveObject
+ nanr.Label = "drill_" + "{0:0{1}}".format(i, 3)
anr.append(nanr)
for o in tbd:
removesubtree([o])
- doc.addObject("Part::Compound","annulars")
- Holes_Compound=doc.ActiveObject
+ doc.addObject("Part::Compound", "annulars")
+ Holes_Compound = doc.ActiveObject
Holes_Compound.Links = anr
- Holes_Compound.ViewObject.Transparency=70
+ Holes_Compound.ViewObject.Transparency = 70
doc.recompute()
- Holes_Compound.ViewObject.ShapeColor = (0.33,1.00,0.00)
- Holes_Compound.Label='TH-Drills'
+ Holes_Compound.ViewObject.ShapeColor = (0.33, 1.00, 0.00)
+ Holes_Compound.Label = "TH-Drills"
# if ar!=0:
# Holes_Compound.Placement.Rotation.Angle = radians(ar)
# tbassembled.append(Holes_Compound)
holesT.ViewObject.Visibility = False
- #stop
-
- #stop
-
- consolePrint('making Top Pads\n')
- pcb.setLayer(0) #'F.Cu')
- topP=pcb.makePads(shape_type='wire',thickness=deltaz,holes=False,fit_arcs=True) #solid',thickness=deltaz,holes=True,fit_arcs=True)
- topPf=None
- topPe=None
- #print(topP.Label)
+ # stop
+
+ # stop
+
+ consolePrint("making Top Pads\n")
+ pcb.setLayer(0) #'F.Cu')
+ topP = pcb.makePads(
+ shape_type="wire",
+ thickness=deltaz,
+ holes=False,
+ fit_arcs=True,
+ ) # solid',thickness=deltaz,holes=True,fit_arcs=True)
+ topPf = None
+ topPe = None
+ # print(topP.Label)
# print(FreeCAD.ActiveDocument.ActiveObject.Label)
- if hasattr(topP, 'OutList'):
+ if hasattr(topP, "OutList"):
topPWs = topP.OutList[0]
s_p = None
for w in topPWs.Shape.Wires:
- #Part.show(w)
+ # Part.show(w)
# Part.show(Part.Face(w))
s = Part.Face(w)
if s_p is not None:
s = s.fuse(s_p)
- s_p=s
- #Part.show(s.extrude(FreeCAD.Vector(0.0, 0.0, deltaz)))
+ s_p = s
+ # Part.show(s.extrude(FreeCAD.Vector(0.0, 0.0, deltaz)))
Part.show(s)
topPf = doc.ActiveObject
# if ar!=0:
# topPf.Placement.Rotation.Angle = radians(ar)
- topPf.Label = 'topPadFace'
+ topPf.Label = "topPadFace"
removesubtree([topP])
s = topPf.Shape
- if hasattr (holesT,'Name'): # cutting holes
+ if hasattr(holesT, "Name"): # cutting holes
s = s.cut(holesT.Shape)
- #Part.show(s)
+ # Part.show(s)
Part.show(s.extrude(FreeCAD.Vector(0.0, 0.0, deltaz)))
topPe = doc.ActiveObject
removesubtree([topPf])
- if hasattr (topPe,'Name'):
- topPe.Label = 'topPads'
- #btmP.ViewObject.Transparency = 50
- topPe.Placement.Base.z-=deltaz
- topPe.ViewObject.Transparency=pads_transparency
+ if hasattr(topPe, "Name"):
+ topPe.Label = "topPads"
+ # btmP.ViewObject.Transparency = 50
+ topPe.Placement.Base.z -= deltaz
+ topPe.ViewObject.Transparency = pads_transparency
topPe.ViewObject.ShapeColor = pads_color
if topPe.Shape.Area != 0:
tbassembled.append(topPe)
else:
removesubtree([topPe])
-
- #stop
- consolePrint('making Bot Pads\n')
- pcb.setLayer(31) #'B.Cu')
- btmP=pcb.makePads(shape_type='wire',thickness=0.01,holes=False,fit_arcs=True)
+
+ # stop
+ consolePrint("making Bot Pads\n")
+ pcb.setLayer(31) #'B.Cu')
+ btmP = pcb.makePads(shape_type="wire", thickness=0.01, holes=False, fit_arcs=True)
btmPf = None
- btmPe=None
- if hasattr(btmP, 'OutList'):
+ btmPe = None
+ if hasattr(btmP, "OutList"):
btmPWs = btmP.OutList[0]
s_p = None
for w in btmPWs.Shape.Wires:
- #Part.show(w)
- #Part.show(Part.Face(w))
+ # Part.show(w)
+ # Part.show(Part.Face(w))
s = Part.Face(w)
if s_p is not None:
s = s.fuse(s_p)
- s_p=s
- #Part.show(s.extrude(FreeCAD.Vector(0.0, 0.0, -deltaz)))
+ s_p = s
+ # Part.show(s.extrude(FreeCAD.Vector(0.0, 0.0, -deltaz)))
Part.show(s)
btmPf = doc.ActiveObject
# if ar!=0:
# btmPf.Placement.Rotation.Angle = radians(ar)
s = btmPf.Shape
- if hasattr (holesT,'Name'): # cutting holes
+ if hasattr(holesT, "Name"): # cutting holes
s = s.cut(holesT.Shape)
- #Part.show(s)
+ # Part.show(s)
Part.show(s.extrude(FreeCAD.Vector(0.0, 0.0, deltaz)))
btmPe = doc.ActiveObject
- if hasattr (btmPe,'Name'):
- btmPe.Label = 'btmPads'
+ if hasattr(btmPe, "Name"):
+ btmPe.Label = "btmPads"
removesubtree([btmP])
removesubtree([btmPf])
# tbassembled.append(btmPe)
- #stop
- #btmP.ViewObject.Transparency = 50
- btmPe.Placement.Base.z-=pcbThickness # -deltaz
- btmPe.ViewObject.Transparency=pads_transparency
+ # stop
+ # btmP.ViewObject.Transparency = 50
+ btmPe.Placement.Base.z -= pcbThickness # -deltaz
+ btmPe.ViewObject.Transparency = pads_transparency
btmPe.ViewObject.ShapeColor = pads_color
if btmPe.Shape.Area != 0:
tbassembled.append(btmPe)
else:
removesubtree([btmPe])
- doc.Tip = doc.addObject('App::DocumentObjectGroup','Group')
- fp_group=doc.ActiveObject
- fp_group.Label = str(fp_name)+'-fp'
-
+ doc.Tip = doc.addObject("App::DocumentObjectGroup", "Group")
+ fp_group = doc.ActiveObject
+ fp_group.Label = str(fp_name) + "-fp"
+
for o in tbassembled:
# doc.getObject(o.Name).adjustRelativeLinks(doc.getObject(fp_group.Name))
doc.getObject(fp_group.Name).addObject(doc.getObject(o.Name))
- #stop
-
- consolePrint('making Top Net Ties\n')
- #net ties
- pcb.setLayer(0) #'F.Cu')
- ntt=pcb.makeNetTies(shape_type='wire',thickness=0.01,fit_arcs=True)
- if hasattr (ntt,'Name'):
+ # stop
+
+ consolePrint("making Top Net Ties\n")
+ # net ties
+ pcb.setLayer(0) #'F.Cu')
+ ntt = pcb.makeNetTies(shape_type="wire", thickness=0.01, fit_arcs=True)
+ if hasattr(ntt, "Name"):
s_p = None
for w in ntt.Shape.Wires:
s = Part.Face(w)
if s_p is not None:
s = s.fuse(s_p)
- s_p=s
+ s_p = s
Part.show(s)
nttF = doc.ActiveObject
removesubtree([ntt])
s = nttF.Shape
- if hasattr (holesT,'Name'): # cutting holes
+ if hasattr(holesT, "Name"): # cutting holes
s = s.cut(holesT.Shape)
- #Part.show(s)
+ # Part.show(s)
nttE = Part.show(s.extrude(FreeCAD.Vector(0.0, 0.0, deltaz)))
removesubtree([nttF])
- nttE.Label = 'topNetTie'
+ nttE.Label = "topNetTie"
nttE.ViewObject.Transparency = nettie_transparency
nttE.ViewObject.ShapeColor = nettie_color
# nttE.Placement.Base.z+=deltaz
# doc.getObject(nttE.Name).adjustRelativeLinks(doc.getObject(fp_group.Name))
doc.getObject(fp_group.Name).addObject(nttE)
- consolePrint('making Bot Net Ties\n')
- pcb.setLayer(31) #'B.Cu')
- ntb=pcb.makeNetTies(shape_type='wire',thickness=0.01,fit_arcs=True)
- if hasattr (ntb,'Name'):
+ consolePrint("making Bot Net Ties\n")
+ pcb.setLayer(31) #'B.Cu')
+ ntb = pcb.makeNetTies(shape_type="wire", thickness=0.01, fit_arcs=True)
+ if hasattr(ntb, "Name"):
s_p = None
for w in ntb.Shape.Wires:
s = Part.Face(w)
if s_p is not None:
s = s.fuse(s_p)
- s_p=s
+ s_p = s
Part.show(s)
ntbF = doc.ActiveObject
removesubtree([ntb])
s = ntbF.Shape
- if hasattr (holesT,'Name'): # cutting holes
+ if hasattr(holesT, "Name"): # cutting holes
s = s.cut(holesT.Shape)
- #Part.show(s)
+ # Part.show(s)
ntbE = Part.show(s.extrude(FreeCAD.Vector(0.0, 0.0, +deltaz)))
removesubtree([ntbF])
- ntbE.Label = 'btmNetTie'
+ ntbE.Label = "btmNetTie"
ntbE.ViewObject.Transparency = nettie_transparency
ntbE.ViewObject.ShapeColor = nettie_color
- ntbE.Placement.Base.z-=(pcbThickness+deltaz)
+ ntbE.Placement.Base.z -= pcbThickness + deltaz
# doc.getObject(ntbE.Name).adjustRelativeLinks(doc.getObject(fp_group.Name))
doc.getObject(fp_group.Name).addObject(ntbE)
if Holes_Compound is not None:
# Holes_Compound.adjustRelativeLinks(doc.getObject(fp_group.Name))
doc.getObject(fp_group.Name).addObject(Holes_Compound)
-
-
- consolePrint('making Drawings sketches\n')
- tbds=[];tbp=[];tltbp=[]
+
+ consolePrint("making Drawings sketches\n")
+ tbds = []
+ tbp = []
# top layers
- pcb.setLayer(37) #'F.Silks')
- sk,tls,tbd=pcb.makeSketches(fit_arcs=True)
- #print(doc, tbd, tbd[0].OutList[0].Name, tbd[0].Name)
+ pcb.setLayer(37) #'F.Silks')
+ sk, tls, tbd = pcb.makeSketches(fit_arcs=True)
+ # print(doc, tbd, tbd[0].OutList[0].Name, tbd[0].Name)
tbds.append(tbd)
- tbp.append((sk,tls))
-
- pcb.setLayer(47) #'F.CrtYd')
- sk,tls,tbd=pcb.makeSketches(fit_arcs=True)
+ tbp.append((sk, tls))
+
+ pcb.setLayer(47) #'F.CrtYd')
+ sk, tls, tbd = pcb.makeSketches(fit_arcs=True)
tbds.append(tbd)
- tbp.append((sk,tls))
-
- pcb.setLayer(49) #'F.Fab')
- sk,tls,tbd=pcb.makeSketches(fit_arcs=True)
+ tbp.append((sk, tls))
+
+ pcb.setLayer(49) #'F.Fab')
+ sk, tls, tbd = pcb.makeSketches(fit_arcs=True)
tbds.append(tbd)
- tbp.append((sk,tls))
-
- pcb.setLayer(44) #'Edge.Cuts')
- sk,tls,tbd=pcb.makeSketches(fit_arcs=True)
+ tbp.append((sk, tls))
+
+ pcb.setLayer(44) #'Edge.Cuts')
+ sk, tls, tbd = pcb.makeSketches(fit_arcs=True)
tbds.append(tbd)
- tbp.append((sk,tls))
-
- pcb.setLayer(45) #'Margins')
- sk,tls,tbd=pcb.makeSketches(fit_arcs=True)
+ tbp.append((sk, tls))
+
+ pcb.setLayer(45) #'Margins')
+ sk, tls, tbd = pcb.makeSketches(fit_arcs=True)
tbds.append(tbd)
- tbp.append((sk,tls))
-
- pcb.setLayer(33) #'F.Adhes')
- sk,tls,tbd=pcb.makeSketches(fit_arcs=True)
+ tbp.append((sk, tls))
+
+ pcb.setLayer(33) #'F.Adhes')
+ sk, tls, tbd = pcb.makeSketches(fit_arcs=True)
tbds.append(tbd)
- tbp.append((sk,tls))
+ tbp.append((sk, tls))
# User layers
- pcb.setLayer(40) #'Dwgs.User')
- sk,tls,tbd=pcb.makeSketches(fit_arcs=True)
+ pcb.setLayer(40) #'Dwgs.User')
+ sk, tls, tbd = pcb.makeSketches(fit_arcs=True)
tbds.append(tbd)
- tbp.append((sk,tls))
-
+ tbp.append((sk, tls))
+
# User layers
- pcb.setLayer(41) #'Cmts.User')
- sk,tls,tbd=pcb.makeSketches(fit_arcs=True)
+ pcb.setLayer(41) #'Cmts.User')
+ sk, tls, tbd = pcb.makeSketches(fit_arcs=True)
tbds.append(tbd)
- tbp.append((sk,tls))
-
+ tbp.append((sk, tls))
+
for l in tbds:
for o in l:
doc.removeObject(o.OutList[0].Name)
doc.removeObject(o.Name)
for t in tbp:
- sk=t[0]
- tl=t[1]
- if hasattr (sk,'Name'):
- sk.Placement.Base.z+=deltaz
+ sk = t[0]
+ tl = t[1]
+ if hasattr(sk, "Name"):
+ sk.Placement.Base.z += deltaz
# if ar!=0:
# sk.Placement.Rotation.Angle = radians(ar)
# sk.adjustRelativeLinks(doc.getObject(fp_group.Name))
doc.getObject(fp_group.Name).addObject(sk)
- if hasattr (tl,'Name'):
- tl.Placement.Base.z+=deltaz
+ if hasattr(tl, "Name"):
+ tl.Placement.Base.z += deltaz
# if ar!=0:
# tl.Placement.Rotation.Angle = radians(ar)
# tl.adjustRelativeLinks(doc.getObject(fp_group.Name))
doc.getObject(fp_group.Name).addObject(tl)
-
- tbds=[];tbp=[]
+
+ tbds = []
+ tbp = []
# btm layers
- pcb.setLayer(36) #'B.Silks')
- sk,tls,tbd=pcb.makeSketches(fit_arcs=True)
+ pcb.setLayer(36) #'B.Silks')
+ sk, tls, tbd = pcb.makeSketches(fit_arcs=True)
tbds.append(tbd)
- tbp.append((sk,tls))
-
- pcb.setLayer(46) #'B.CrtYd')
- sk,tls,tbd=pcb.makeSketches(fit_arcs=True)
+ tbp.append((sk, tls))
+
+ pcb.setLayer(46) #'B.CrtYd')
+ sk, tls, tbd = pcb.makeSketches(fit_arcs=True)
tbds.append(tbd)
- tbp.append((sk,tls))
-
- pcb.setLayer(48) #'B.Fab')
- sk,tls,tbd=pcb.makeSketches(fit_arcs=True)
+ tbp.append((sk, tls))
+
+ pcb.setLayer(48) #'B.Fab')
+ sk, tls, tbd = pcb.makeSketches(fit_arcs=True)
tbds.append(tbd)
- tbp.append((sk,tls))
+ tbp.append((sk, tls))
+
+ # stop
- #stop
-
for l in tbds:
for o in l:
doc.removeObject(o.OutList[0].Name)
doc.removeObject(o.Name)
for t in tbp:
- sk=t[0]
- tl=t[1]
- if hasattr (sk,'Name'):
- sk.Placement.Base.z-=pcbThickness-deltaz
+ sk = t[0]
+ tl = t[1]
+ if hasattr(sk, "Name"):
+ sk.Placement.Base.z -= pcbThickness - deltaz
# if ar!=0:
# sk.Placement.Rotation.Angle = radians(ar)
# sk.adjustRelativeLinks(doc.getObject(fp_group.Name))
doc.getObject(fp_group.Name).addObject(sk)
- if hasattr (tl,'Name'):
- tl.Placement.Base.z-=pcbThickness-deltaz
+ if hasattr(tl, "Name"):
+ tl.Placement.Base.z -= pcbThickness - deltaz
# if ar!=0:
# tl.Placement.Rotation.Angle = radians(ar)
# tl.adjustRelativeLinks(doc.getObject(fp_group.Name))
doc.getObject(fp_group.Name).addObject(tl)
if fp_group is not None:
- doc.addObject("Part::Compound","TCompound")
+ doc.addObject("Part::Compound", "TCompound")
TComp = doc.ActiveObject
TComp.Links = fp_group.OutList
doc.recompute()
@@ -829,18 +884,30 @@ def addfootprint(fname = None):
delta = 0.5
centerX = bbComp.Center.x
centerY = bbComp.Center.y
- pcb_XL = bbComp.XLength*(1+delta)
- pcb_YL = bbComp.YLength*(1+delta)
- pcb_ZL = pcbThickness-2*deltaz
- pcb=FreeCAD.ActiveDocument.addObject('Part::Feature','PCB')
+ pcb_XL = bbComp.XLength * (1 + delta)
+ pcb_YL = bbComp.YLength * (1 + delta)
+ pcb_ZL = pcbThickness - 2 * deltaz
+ pcb = FreeCAD.ActiveDocument.addObject("Part::Feature", "PCB")
for o in fp_group.OutList:
o.ViewObject.Visibility = True
try:
- if hasattr (holesT,'Name'):
- pcb.Shape=Part.makeBox(pcb_XL, pcb_YL, pcb_ZL, FreeCAD.Vector(centerX-pcb_XL/2,centerY-pcb_YL/2,-(pcb_ZL+deltaz)), FreeCAD.Vector(0,0,1)).cut(holesT.Shape)
+ if hasattr(holesT, "Name"):
+ pcb.Shape = Part.makeBox(
+ pcb_XL,
+ pcb_YL,
+ pcb_ZL,
+ FreeCAD.Vector(centerX - pcb_XL / 2, centerY - pcb_YL / 2, -(pcb_ZL + deltaz)),
+ FreeCAD.Vector(0, 0, 1),
+ ).cut(holesT.Shape)
removesubtree([holesT])
else:
- pcb.Shape=Part.makeBox(pcb_XL, pcb_YL, pcb_ZL, FreeCAD.Vector(centerX-pcb_XL/2,centerY-pcb_YL/2,-(pcb_ZL+deltaz)), FreeCAD.Vector(0,0,1))
+ pcb.Shape = Part.makeBox(
+ pcb_XL,
+ pcb_YL,
+ pcb_ZL,
+ FreeCAD.Vector(centerX - pcb_XL / 2, centerY - pcb_YL / 2, -(pcb_ZL + deltaz)),
+ FreeCAD.Vector(0, 0, 1),
+ )
pcb.ViewObject.Transparency = pcb_transparency
pcb.ViewObject.ShapeColor = mkColor(pcb_col)
# pcb.adjustRelativeLinks(doc.getObject(fp_group.Name))
@@ -848,27 +915,33 @@ def addfootprint(fname = None):
doc.recompute()
except:
doc.removeObject(pcb.Name)
- consolePrint('no shapes generated\n')
- if len(rotations) >0:
+ consolePrint("no shapes generated\n")
+ if len(rotations) > 0:
# print('rotations',rotations)
# makeAnno (name,bp,txt,afs):
- anno = makeAnno('model3D rotations',FreeCAD.Vector(centerX+pcb_XL/2,centerY+pcb_YL/2,0),"model3D rotations:",annotation_fontsize)
- #anno.LabelText.append("\'model3D rotations\'")
- msg="""model3D rotations ...
"""
+ anno = makeAnno(
+ "model3D rotations",
+ FreeCAD.Vector(centerX + pcb_XL / 2, centerY + pcb_YL / 2, 0),
+ "model3D rotations:",
+ annotation_fontsize,
+ )
+ # anno.LabelText.append("\'model3D rotations\'")
+ msg = """model3D rotations ...
"""
for r in rotations:
# anno.LabelText.append(str(r))
- anno.LabelText=anno.LabelText+[str(r)]
- msg+=str(r)+"
"
+ anno.LabelText = [*anno.LabelText, str(r)]
+ msg += str(r) + "
"
# print('anno.LabelText',anno.LabelText)
# 'model3D rotations\n'+str(rotations).strip('[').strip(']')
doc.getObject(fp_group.Name).addObject(anno)
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Info ...",msg)
+ QtGui.QMessageBox.information(None, "Info ...", msg)
doc.commitTransaction()
-
+
if FreeCAD.ActiveDocument is not None:
FreeCADGui.SendMsgToActiveView("ViewFit")
- #FreeCADGui.ActiveDocument.activeView().viewAxonometric()
+ # FreeCADGui.ActiveDocument.activeView().viewAxonometric()
+
###
diff --git a/hlp.py b/hlp.py
index ef9c54d..47ac90d 100644
--- a/hlp.py
+++ b/hlp.py
@@ -1,20 +1,20 @@
-# -*- coding: utf-8 -*-
# ****************************************************************************
global ksuWBpath
-import ksu_locator, os
+import os
+
+import ksu_locator
ksuWBpath = os.path.dirname(ksu_locator.__file__)
# font_color = ""
-import FreeCAD, FreeCADGui
+import FreeCADGui
# paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/MainWindow")
# if 'dark' in paramGet.GetString("StyleSheet").lower(): #we are using a StyleSheet
# font_color = ""
-from PySide import QtGui
from TranslateUtils import translate
font_color = ""
diff --git a/kicadStepUpCMD.py b/kicadStepUpCMD.py
index 2f4e91a..422220a 100644
--- a/kicadStepUpCMD.py
+++ b/kicadStepUpCMD.py
@@ -1,132 +1,142 @@
-# -*- coding: utf-8 -*-
-#****************************************************************************
-#* *
-#* Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
-#* 3D exporter for FreeCAD *
-#* Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
-#* Copyright (c) 2015 *
-#* Maurice easyw@katamail.com *
-#* *
-#* Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
-#* *
-
-import FreeCAD, FreeCADGui, Part
-from FreeCAD import Base
-import os, sys, tempfile, re
-import Draft, DraftGeomUtils #, OpenSCAD2Dgeom
+# ****************************************************************************
+# * *
+# * Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
+# * 3D exporter for FreeCAD *
+# * Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
+# * Copyright (c) 2015 *
+# * Maurice easyw@katamail.com *
+# * *
+# * Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
+# * *
+
+import os
+import sys
+import tempfile
+
+import Draft
+import DraftGeomUtils # , OpenSCAD2Dgeom
+import FreeCAD
+import FreeCADGui
+import Part
import PySide
-from PySide import QtGui, QtCore
+from FreeCAD import Base
+from PySide import QtCore, QtGui
from PySide.QtCore import QT_TRANSLATE_NOOP
+
from TranslateUtils import translate
QtWidgets = QtGui
-from pivy import coin
-from threading import Timer
-
-import ksu_locator
# from kicadStepUptools import onLoadBoard, onLoadFootprint
import math
-from math import sqrt
+from threading import Timer
-import constrainator
+from pivy import coin
+
+import ksu_locator
from constrainator import add_constraints, sanitizeSkBsp
-ksuCMD_version__='2.5.7'
+ksuCMD_version__ = "2.5.7"
global invisible_objs
-invisible_objs=[]
+invisible_objs = []
-precision = 0.1 # precision in spline or bezier conversion
-q_deflection = 0.02 # quasi deflection parameter for discretization
+precision = 0.1 # precision in spline or bezier conversion
+q_deflection = 0.02 # quasi deflection parameter for discretization
hide_compound = True
-reload_Gui=False#True
+reload_Gui = False # True
a3 = False
try:
- from freecad.asm3 import assembly as asm
- FreeCAD.Console.PrintWarning('A3 available\n')
+ FreeCAD.Console.PrintWarning("A3 available\n")
a3 = True
except:
# FreeCAD.Console.PrintWarning('A3 not available\n')
a3 = False
try:
- from PathScripts.PathUtils import horizontalEdgeLoop
- from PathScripts.PathUtils import horizontalFaceLoop
- from PathScripts.PathUtils import loopdetect
import PathCommands
except:
- FreeCAD.Console.PrintError('Path WB not found\n')
+ FreeCAD.Console.PrintError("Path WB not found\n")
+
def reload_lib(lib):
- if (sys.version_info > (3, 0)):
- import importlib
- importlib.reload(lib)
- else:
- reload (lib)
+ import importlib
+
+ importlib.reload(lib)
-use_outerwire = False #False #True
-remove_shapes = True #False #True
-hide_objects = True #False # True
-use_draft = True #False # True use Draft.makesketch
-attach_sketch = False #True
-create_plane = False# True #False
+
+use_outerwire = False # False #True
+remove_shapes = True # False #True
+hide_objects = True # False # True
+use_draft = True # False # True use Draft.makesketch
+attach_sketch = False # True
+create_plane = False # True #False
conv_started = False
global max_geo_admitted
-max_geo_admitted = 1500 # after this number, no recompute is applied
+max_geo_admitted = 1500 # after this number, no recompute is applied
global restore_specular_cls, restore_light
+import contextlib
+import functools
+import operator
from sys import platform as _platform
-pt_lnx=False
+pt_lnx = False
# window GUI dimensions parameters
if _platform == "linux" or _platform == "linux2":
- # linux
- pt_lnx=True
- sizeXmin=172;sizeYmin=34+34
- sizeX=172;sizeY=516 #536
- sizeXright=172;sizeYright=536 #556
+ # linux
+ pt_lnx = True
+ sizeXmin = 172
+ sizeYmin = 34 + 34
+ sizeX = 172
+ sizeY = 516 # 536
+ sizeXright = 172
+ sizeYright = 536 # 556
else:
- sizeXmin=172;sizeYmin=34
- sizeX=172;sizeY=482#502
- sizeXright=172;sizeYright=502#522
+ sizeXmin = 172
+ sizeYmin = 34
+ sizeX = 172
+ sizeY = 482 # 502
+ sizeXright = 172
+ sizeYright = 502 # 522
if _platform == "darwin":
- pt_osx=True
+ pt_osx = True
+
-def P_Line(prm1,prm2):
- if hasattr(Part,"LineSegment"):
+def P_Line(prm1, prm2):
+ if hasattr(Part, "LineSegment"):
return Part.LineSegment(prm1, prm2)
- else:
- return Part.Line(prm1, prm2)
+ return Part.Line(prm1, prm2)
+
def fuse_objs(GuiObjSel):
- objList= []
+ objList = []
for s in GuiObjSel:
objList.append(s.Object)
- FreeCAD.ActiveDocument.addObject("Part::MultiFuse","MultiFuse")
+ FreeCAD.ActiveDocument.addObject("Part::MultiFuse", "MultiFuse")
MultiFuseName = FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.getObject(MultiFuseName).Shapes = objList
# [App.activeDocument().Part__Feature002,App.activeDocument().Part__Feature003,App.activeDocument().Part__Feature004,App.activeDocument().Part__Feature005,App.activeDocument().Part__Feature006,App.activeDocument().Part__Feature007,App.activeDocument().Part__Feature008,App.activeDocument().Part__Feature009,App.activeDocument().Part__Feature010,App.activeDocument().Part__Feature011,]
FreeCAD.ActiveDocument.recompute()
return MultiFuseName
-#
+
def rmvsubtree(objs):
- def addsubobjs(obj,toremoveset):
+ def addsubobjs(obj, toremoveset):
toremove.add(obj)
- if hasattr(obj,'OutList'):
+ if hasattr(obj, "OutList"):
for subobj in obj.OutList:
- addsubobjs(subobj,toremoveset)
- import FreeCAD
- toremove=set()
+ addsubobjs(subobj, toremoveset)
+
+ toremove = set()
for obj in objs:
- addsubobjs(obj,toremove)
- checkinlistcomplete =False
+ addsubobjs(obj, toremove)
+ checkinlistcomplete = False
while not checkinlistcomplete:
for obj in toremove:
if (obj not in objs) and (frozenset(obj.InList) - toremove):
@@ -135,60 +145,57 @@ def addsubobjs(obj,toremoveset):
else:
checkinlistcomplete = True
for obj in toremove:
- try:
+ with contextlib.suppress(BaseException):
obj.Document.removeObject(obj.Name)
- except:
- pass
+
+
###
def info_msg(msg):
- QtGui.QApplication.restoreOverrideCursor()
- # msg="""Select a Compound or
a Part Design group
or more than one Part object !
"""
- spc="""*******************************************************************************
- """
- msg1="Info ..."
- QtGui.QApplication.restoreOverrideCursor()
- #RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Information,
- msg1,
- msg)
- diag.setWindowModality(QtCore.Qt.ApplicationModal)
- diag.exec_()
+ QtGui.QApplication.restoreOverrideCursor()
+ # msg="""Select a Compound or
a Part Design group
or more than one Part object !
"""
+ msg1 = "Info ..."
+ QtGui.QApplication.restoreOverrideCursor()
+ # RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
+ diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Information, msg1, msg)
+ diag.setWindowModality(QtCore.Qt.ApplicationModal)
+ diag.exec_()
+
+
##
ksuWBpath = os.path.dirname(ksu_locator.__file__)
-#sys.path.append(ksuWB + '/Gui')
-ksuWB_icons_path = os.path.join( ksuWBpath, 'Resources', 'icons')
+# sys.path.append(ksuWB + '/Gui')
+ksuWB_icons_path = os.path.join(ksuWBpath, "Resources", "icons")
-#__dir__ = os.path.dirname(__file__)
-#iconPath = os.path.join( __dir__, 'Resources', 'icons' )
+# __dir__ = os.path.dirname(__file__)
+# iconPath = os.path.join( __dir__, 'Resources', 'icons' )
-def getTopLevel (obj):
- lvl=10000
- top=None
- if hasattr(obj,'InListRecursive'):
+
+def getTopLevel(obj):
+ lvl = 10000
+ top = None
+ if hasattr(obj, "InListRecursive"):
for ap in obj.InListRecursive:
- if hasattr(ap,'Placement'):
- if len(ap.InListRecursive) < lvl:
- top = ap
- lvl = len(ap.InListRecursive)
- #else:
+ if hasattr(ap, "Placement") and len(ap.InListRecursive) < lvl:
+ top = ap
+ lvl = len(ap.InListRecursive)
+ # else:
# sayerr(obj.Label)
- #top = obj
+ # top = obj
return top
+
+
##
-def getSortedList (obj):
- lvl=10000
- completed=0
- listUs=obj.InListRecursive
- #sayerr('unsorted')
- #for p in listUs:
+def getSortedList(obj):
+ lvl = 10000
+ # sayerr('unsorted')
+ # for p in listUs:
# print p.Label
- listUsName=[]
+ listUsName = []
for o in obj.InListRecursive:
listUsName.append(o.Name)
- listS=[]
- i=0
- #for i, ap in enumerate(listUs):
+ listS = []
+ # for i, ap in enumerate(listUs):
# top=ap
# if len(ap.InListRecursive) < lvl:
# lvl = len(ap.InListRecursive)
@@ -197,301 +204,305 @@ def getSortedList (obj):
# top = ap2
# lvl = len(ap2.InListRecursive)
# listS.append(top)
- #sayw(listUsName)
- i=0
- while len (listUsName) > 0:
+ # sayw(listUsName)
+ while len(listUsName) > 0:
for apName in listUsName:
- #apName=listUsName[i]
- ap=FreeCAD.ActiveDocument.getObject(apName)
+ # apName=listUsName[i]
+ ap = FreeCAD.ActiveDocument.getObject(apName)
if len(ap.InListRecursive) < lvl:
lvl = len(ap.InListRecursive)
top = ap
topName = ap.Name
listS.append(top)
- #print topName
- idx=listUsName.index(topName)
- #sayw(idx)
+ # print topName
+ idx = listUsName.index(topName)
+ # sayw(idx)
listUsName.pop(idx)
- lvl=10000
- #sayerr(listUsName)
+ lvl = 10000
+ # sayerr(listUsName)
return listS
+
+
##
-def getNormalPlacementHierarchy (sel0):
+def getNormalPlacementHierarchy(sel0):
"""get normal at face and placement relative to hierarchy
- of first selection object/face
- return normal, placement, topObj, bbox center absolute"""
+ of first selection object/face
+ return normal, placement, topObj, bbox center absolute"""
- import Draft
from FreeCAD import Base
+
use_hierarchy = True
-
- Obj=sel0.Object
- subObj=sel0.SubObjects[0]
- edge_op=0
+
+ Obj = sel0.Object
+ subObj = sel0.SubObjects[0]
+ edge_op = 0
top_level_obj = getTopLevel(Obj)
- if top_level_obj is not None: #hierarchy object
+ if top_level_obj is not None: # hierarchy object
# say('Hierarchy obj')
- pad=0
- open_circle=False
- if 'Face' in str(subObj):
+ pad = 0
+ open_circle = False
+ if "Face" in str(subObj):
# say('Hierarchy obj Face')
- pad=0 #face
- elif 'Edge' in str(subObj):
+ pad = 0 # face
+ elif "Edge" in str(subObj):
wire = Part.Wire(subObj)
if subObj.isClosed():
subObj = Part.Face(wire)
else:
# sayerr(str(subObj.Curve))
- if 'Circle' in str(subObj.Curve):
+ if "Circle" in str(subObj.Curve):
# sayerr('Circle radius '+str(subObj.Curve.Radius))
- #f1=subObj.Shape.Faces[0]
+ # f1=subObj.Shape.Faces[0]
wf = Part.Face(Part.Wire(subObj))
Part.show(wf)
- wf_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ wf_name = FreeCAD.ActiveDocument.ActiveObject.Name
- dirz=wf.normalAt(0,0)
+ dirz = wf.normalAt(0, 0)
# ccircle = Part.makeCircle(r, Base.Vector(cnt), Base.Vector(dirz))
# > Circle (Radius : 10, Position : (10, 0, 0), Direction : (1, 0, 0))
ccircle = Part.makeCircle(subObj.Curve.Radius, Base.Vector(subObj.Curve.Center), Base.Vector(dirz))
- #ccircle_face = Part.Face(ccircle)
- #Part.show(ccircle_face)
- #ccircle_face_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #FreeCAD.ActiveDocument.getObject(ccircle_face_name).Label='ccircle_face'
+ # ccircle_face = Part.Face(ccircle)
+ # Part.show(ccircle_face)
+ # ccircle_face_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ # FreeCAD.ActiveDocument.getObject(ccircle_face_name).Label='ccircle_face'
Part.show(ccircle)
- ccircle_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.getObject(ccircle_name).Label='ccircle'
- f2=Part.Face(Part.Wire((FreeCAD.ActiveDocument.getObject(ccircle_name).Shape.Edges[0])))
+ ccircle_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.getObject(ccircle_name).Label = "ccircle"
+ f2 = Part.Face(Part.Wire(FreeCAD.ActiveDocument.getObject(ccircle_name).Shape.Edges[0]))
Part.show(f2)
- f2_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ f2_name = FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.removeObject(ccircle_name)
FreeCAD.ActiveDocument.removeObject(wf_name)
# ccircle.Curve
# > Circle (Radius : 10, Position : (10, 0, 0), Direction : (1, 0, 0))
bbxCenter = subObj.Curve.Center
- norm = f2.normalAt(0,0)
+ norm = f2.normalAt(0, 0)
subObj = f2
FreeCAD.ActiveDocument.removeObject(f2_name)
- #PC1=Draft.makePoint(subObj.Curve.Center)
- #w.close
- open_circle=True
+ # PC1=Draft.makePoint(subObj.Curve.Center)
+ # w.close
+ open_circle = True
else:
subObj = wire
- #subObj = wire
- edge_op=1
- pad=1 #edge
+ # subObj = wire
+ edge_op = 1
+ pad = 1 # edge
if use_hierarchy:
nwshp = subObj.copy()
- pOriginal=subObj.Placement
- if 'Datum' not in str(Obj.Name):
- p0 = FreeCAD.Placement (FreeCAD.Vector(0,0,0), FreeCAD.Rotation(0,0,0), FreeCAD.Vector(0,0,0))
- nwshp.Placement=p0
- r=[]
- t=nwshp.copy()
- #resetting Placement
+ pOriginal = subObj.Placement
+ if "Datum" not in str(Obj.Name):
+ p0 = FreeCAD.Placement(FreeCAD.Vector(0, 0, 0), FreeCAD.Rotation(0, 0, 0), FreeCAD.Vector(0, 0, 0))
+ nwshp.Placement = p0
+ r = []
+ t = nwshp.copy()
+ # resetting Placement
for i in t.childShapes():
- c=i.copy()
- c.Placement=t.Placement.multiply(c.Placement)
- r.append((i,c))
- acpy=t.replaceShape(r)
- acpy.Placement=FreeCAD.Placement()
- if hasattr(Obj,'InListRecursive'):
- lrl=len(Obj.InListRecursive)
+ c = i.copy()
+ c.Placement = t.Placement.multiply(c.Placement)
+ r.append((i, c))
+ acpy = t.replaceShape(r)
+ acpy.Placement = FreeCAD.Placement()
+ if hasattr(Obj, "InListRecursive"):
+ lrl = len(Obj.InListRecursive)
# for o_ in Obj.InListRecursive:
# say(o_.Name)
if len(Obj.InList):
top_level_obj = getTopLevel(Obj)
- #sayerr(top_level_obj[j].Label)
- listSorted=getSortedList (Obj)
- #for p in listSorted:
+ # sayerr(top_level_obj[j].Label)
+ listSorted = getSortedList(Obj)
+ # for p in listSorted:
# print p.Name
- #print listSorted, ' Sorted; Top ', top_level_obj[j]
- #stop
- for i in range (0,lrl):
- if hasattr(listSorted[i],'Placement'):
- #if 'Plane' not in ob.InListRecursive[i].TypeId:
+ # print listSorted, ' Sorted; Top ', top_level_obj[j]
+ # stop
+ for i in range(lrl):
+ if hasattr(listSorted[i], "Placement"):
+ # if 'Plane' not in ob.InListRecursive[i].TypeId:
if listSorted[i].hasExtension("App::GeoFeatureGroupExtension"):
- acpy.Placement=acpy.Placement.multiply(listSorted[i].Placement)
+ acpy.Placement = acpy.Placement.multiply(listSorted[i].Placement)
# say(acpy.Placement)
- #acpy.Placement=acpy.Placement.multiply(pOriginal)
- #acpy.Placement=acpy.Placement.multiply(pOriginal)
- if pad == 0: #note making wire from edge already resets the original placement
- acpy.Placement=acpy.Placement.multiply(pOriginal)
+ # acpy.Placement=acpy.Placement.multiply(pOriginal)
+ # acpy.Placement=acpy.Placement.multiply(pOriginal)
+ if pad == 0: # note making wire from edge already resets the original placement
+ acpy.Placement = acpy.Placement.multiply(pOriginal)
nwshp.Placement = acpy.Placement
- if open_circle==True:
- nwnorm = nwshp.normalAt(0,0)
- elif edge_op==1:
+ if open_circle:
+ nwnorm = nwshp.normalAt(0, 0)
+ elif edge_op == 1:
nwnorm = (nwshp.Vertex2.Point - nwshp.Vertex1.Point).normalize()
else:
- nwnorm = nwshp.normalAt(0,0)
+ nwnorm = nwshp.normalAt(0, 0)
bbxCenter = nwshp.BoundBox.Center
else:
nwshp = subObj.copy()
- if open_circle==True:
- nwnorm = nwshp.normalAt(0,0)
- elif edge_op==1:
+ if open_circle:
+ nwnorm = nwshp.normalAt(0, 0)
+ elif edge_op == 1:
nwnorm = (subObj.Vertex2.Point - subObj.Vertex1.Point).normalize()
else:
- nwnorm = nwshp.normalAt(0,0)
+ nwnorm = nwshp.normalAt(0, 0)
bbxCenter = nwshp.BoundBox.Center
return nwnorm, nwshp.Placement, top_level_obj, bbxCenter
- elif 'Face' in str(subObj) or 'Edge' in str(subObj): # not in hierarchy
+ if "Face" in str(subObj) or "Edge" in str(subObj): # not in hierarchy
# say('Part obj')
- pad=0 #face
- open_circle=False
- if 'Edge' in str(subObj):
+ pad = 0 # face
+ open_circle = False
+ if "Edge" in str(subObj):
wire = Part.Wire(subObj)
if subObj.isClosed():
subObj = Part.Face(wire)
- norm = subObj.normalAt(0,0)
+ norm = subObj.normalAt(0, 0)
bbxCenter = subObj.BoundBox.Center
+ # sayerr(str(subObj.Curve))
+ elif "Circle" in str(subObj.Curve):
+ # sayerr('Circle radius '+str(subObj.Curve.Radius))
+ # f1=subObj.Shape.Faces[0]
+
+ wf = Part.Face(Part.Wire(subObj))
+ Part.show(wf)
+ wf_name = FreeCAD.ActiveDocument.ActiveObject.Name
+
+ dirz = wf.normalAt(0, 0)
+ # ccircle = Part.makeCircle(r, Base.Vector(cnt), Base.Vector(dirz))
+ # > Circle (Radius : 10, Position : (10, 0, 0), Direction : (1, 0, 0))
+ ccircle = Part.makeCircle(subObj.Curve.Radius, Base.Vector(subObj.Curve.Center), Base.Vector(dirz))
+ # ccircle_face = Part.Face(ccircle)
+ # Part.show(ccircle_face)
+ # ccircle_face_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ # FreeCAD.ActiveDocument.getObject(ccircle_face_name).Label='ccircle_face'
+ Part.show(ccircle)
+ ccircle_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.getObject(ccircle_name).Label = "ccircle"
+ f2 = Part.Face(Part.Wire(FreeCAD.ActiveDocument.getObject(ccircle_name).Shape.Edges[0]))
+ Part.show(f2)
+ f2_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.removeObject(ccircle_name)
+ FreeCAD.ActiveDocument.removeObject(wf_name)
+ # ccircle.Curve
+ # > Circle (Radius : 10, Position : (10, 0, 0), Direction : (1, 0, 0))
+ bbxCenter = subObj.Curve.Center
+
+ norm = f2.normalAt(0, 0)
+ # subObj = f2
+ FreeCAD.ActiveDocument.removeObject(f2_name)
+ # PC1=Draft.makePoint(subObj.Curve.Center)
+ # w.close
else:
- # sayerr(str(subObj.Curve))
- if 'Circle' in str(subObj.Curve):
- # sayerr('Circle radius '+str(subObj.Curve.Radius))
- #f1=subObj.Shape.Faces[0]
-
- wf = Part.Face(Part.Wire(subObj))
- Part.show(wf)
- wf_name=FreeCAD.ActiveDocument.ActiveObject.Name
-
- dirz=wf.normalAt(0,0)
- # ccircle = Part.makeCircle(r, Base.Vector(cnt), Base.Vector(dirz))
- # > Circle (Radius : 10, Position : (10, 0, 0), Direction : (1, 0, 0))
- ccircle = Part.makeCircle(subObj.Curve.Radius, Base.Vector(subObj.Curve.Center), Base.Vector(dirz))
- #ccircle_face = Part.Face(ccircle)
- #Part.show(ccircle_face)
- #ccircle_face_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #FreeCAD.ActiveDocument.getObject(ccircle_face_name).Label='ccircle_face'
- Part.show(ccircle)
- ccircle_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.getObject(ccircle_name).Label='ccircle'
- f2=Part.Face(Part.Wire((FreeCAD.ActiveDocument.getObject(ccircle_name).Shape.Edges[0])))
- Part.show(f2)
- f2_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.removeObject(ccircle_name)
- FreeCAD.ActiveDocument.removeObject(wf_name)
- # ccircle.Curve
- # > Circle (Radius : 10, Position : (10, 0, 0), Direction : (1, 0, 0))
- bbxCenter = subObj.Curve.Center
-
- norm = f2.normalAt(0,0)
- #subObj = f2
- FreeCAD.ActiveDocument.removeObject(f2_name)
- #PC1=Draft.makePoint(subObj.Curve.Center)
- #w.close
- else:
- norm = (subObj.Vertex2.Point - subObj.Vertex1.Point).normalize()
- bbxCenter = subObj.BoundBox.Center
- pad=1 #edge
+ norm = (subObj.Vertex2.Point - subObj.Vertex1.Point).normalize()
+ bbxCenter = subObj.BoundBox.Center
+ pad = 1 # edge
else:
- norm = subObj.normalAt(0,0)
+ norm = subObj.normalAt(0, 0)
bbxCenter = subObj.BoundBox.Center
- top_level_obj=None
- #sayerr(str(norm)+str(Obj.Placement)+str(bbxCenter)+str(top_level_obj))
+ top_level_obj = None
+ # sayerr(str(norm)+str(Obj.Placement)+str(bbxCenter)+str(top_level_obj))
return norm, Obj.Placement, top_level_obj, bbxCenter
+ return None
+
##
def ksu_edges2sketch():
global conv_started, max_geo_admitted
-
- cp_edges = [];cp_edges_names = []
- cp_edges_shapes = []; cp_edges_obj = []
- cp_obj = []; cp_obj_name = []
- cp_points = []; cp_faces = []
+
+ cp_edges = []
+ cp_edges_names = []
+ cp_edges_shapes = []
+ cp_edges_obj = []
+ cp_obj = []
+ cp_obj_name = []
+ cp_points = []
+ cp_faces = []
wires = []
- doc=FreeCAD.ActiveDocument
+ doc = FreeCAD.ActiveDocument
docG = FreeCADGui.ActiveDocument
- en = None
- selEx=FreeCADGui.Selection.getSelectionEx()
+ selEx = FreeCADGui.Selection.getSelectionEx()
import Draft
- if len (selEx) > 0:
+
+ if len(selEx) > 0:
for selEdge in selEx:
if not (conv_started):
- doc.openTransaction('e2sk')
+ doc.openTransaction("e2sk")
conv_started = True
- for i,e in enumerate(selEdge.SubObjects):
- if 'Edge' in selEdge.SubElementNames[i]:
+ for i, e in enumerate(selEdge.SubObjects):
+ if "Edge" in selEdge.SubElementNames[i]:
cp_edges.append(e)
- #cp_edges_shapes.append(e.toShape())
+ # cp_edges_shapes.append(e.toShape())
Part.show(Part.Wire(e))
cp = doc.ActiveObject
cp_edges_obj.append(cp)
- #print(cp)
- cp_edges_names.append(selEdge.ObjectName+'.'+selEdge.SubElementNames[i])
+ # print(cp)
+ cp_edges_names.append(selEdge.ObjectName + "." + selEdge.SubElementNames[i])
cp_obj.append(selEdge.Object)
cp_edges_shapes.append(selEdge.Object.Shape)
cp_obj_name.append(selEdge.ObjectName)
if create_plane:
- for v in cp.Shape.Vertexes[:3]: #selEdge.Object.Shape.Vertexes[:3]:
+ for v in cp.Shape.Vertexes[:3]: # selEdge.Object.Shape.Vertexes[:3]:
if v.Point not in cp_points:
cp_points.append(v.Point)
- if len (cp_points) > 2:
- break
- #FreeCAD.Console.PrintMessage(selEdge.ObjectName);FreeCAD.Console.PrintMessage('\n')
- FreeCAD.Console.PrintMessage(selEdge.ObjectName+'.'+selEdge.SubElementNames[i])
- FreeCAD.Console.PrintMessage('\n')
+ if len(cp_points) > 2:
+ break
+ # FreeCAD.Console.PrintMessage(selEdge.ObjectName);FreeCAD.Console.PrintMessage('\n')
+ FreeCAD.Console.PrintMessage(selEdge.ObjectName + "." + selEdge.SubElementNames[i])
+ FreeCAD.Console.PrintMessage("\n")
if hide_objects:
docG.getObject(selEdge.ObjectName).Visibility = False
- #FreeCAD.Console.PrintMessage(e);FreeCAD.Console.PrintMessage('\n')
- #cp_e = Part.show(Part.Wire(e))
+ # FreeCAD.Console.PrintMessage(e);FreeCAD.Console.PrintMessage('\n')
+ # cp_e = Part.show(Part.Wire(e))
wire = Part.Wire(e)
- #cp_edges_shapes.append(wire.toShape())
- wires.append (wire)
- elif 'Face' in selEdge.SubElementNames[i]:
- #o.Shape.Faces
+ # cp_edges_shapes.append(wire.toShape())
+ wires.append(wire)
+ elif "Face" in selEdge.SubElementNames[i]:
+ # o.Shape.Faces
cp_faces.append(e)
if use_outerwire:
- ow=e.OuterWire
- wires.append (ow)
- #es = ow.Edges
- for _e in ow.Edges:
- cp_edges.append(_e)
+ ow = e.OuterWire
+ wires.append(ow)
+ # es = ow.Edges
+ cp_edges.extend(ow.Edges)
Part.show(ow)
cp = doc.ActiveObject
cp_edges_obj.append(cp)
if create_plane:
- for v in cp.Vertexes[:3]: #selEdge.Object.Shape.Vertexes[:3]:
- print('point')
+ for v in cp.Vertexes[:3]: # selEdge.Object.Shape.Vertexes[:3]:
+ print("point")
if v.Point not in cp_points:
cp_points.append(v.Point)
- if len (cp_points) > 2:
+ if len(cp_points) > 2:
break
- else:
- ws=e.Wires
- wires.append (ws)
- #es=e.Edges
+ else:
+ ws = e.Wires
+ wires.append(ws)
+ # es=e.Edges
if create_plane:
- for v in e.Vertexes[:3]: #selEdge.Object.Shape.Vertexes[:3]:
+ for v in e.Vertexes[:3]: # selEdge.Object.Shape.Vertexes[:3]:
print(v.Point)
- if len (cp_points) > 2:
+ if len(cp_points) > 2:
break
if v.Point not in cp_points:
cp_points.append(v.Point)
for w in ws:
- for _e in w.Edges:
- cp_edges.append(_e)
+ cp_edges.extend(w.Edges)
Part.show(w)
cp = doc.ActiveObject
cp_edges_obj.append(cp)
if hide_objects:
docG.getObject(selEdge.ObjectName).Visibility = False
- #for ed in es:
+ # for ed in es:
# Part.show(ed)
- elif 'Vertex' in selEdge.SubElementNames[i]:
- #print(selEdge.SubElementNames[i])
- #print(selEdge.Object.Shape.Volume)
+ elif "Vertex" in selEdge.SubElementNames[i]:
+ # print(selEdge.SubElementNames[i])
+ # print(selEdge.Object.Shape.Volume)
if selEdge.Object.Shape.Volume == 0:
- print('outline selected')
- #for _e in selEdge.Object.Shape.Edges:
+ print("outline selected")
+ # for _e in selEdge.Object.Shape.Edges:
# Part.show(_e.Curve.toShape())
# cp_edges.append(_e)
# cp_edges_shapes.append(e.toShape())
@@ -501,70 +512,67 @@ def ksu_edges2sketch():
cp_edges_obj.append(selEdge.Object.Shape.copy())
if hide_objects:
docG.getObject(selEdge.ObjectName).Visibility = False
-
- if len (cp_edges_obj) >0: # (wires) >0:
+
+ if len(cp_edges_obj) > 0: # (wires) >0:
if not (use_draft):
- FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Sketch')
- #FreeCAD.activeDocument().Sketch.MapMode = "ObjectXY"
- #doc.recompute()
+ FreeCAD.activeDocument().addObject("Sketcher::SketchObject", "Sketch")
+ # FreeCAD.activeDocument().Sketch.MapMode = "ObjectXY"
+ # doc.recompute()
sketch = doc.ActiveObject
sketch.Label = "Sketch_converted"
- if len (cp_edges_obj) > 1:
- doc.addObject("Part::MultiFuse","union")
+ if len(cp_edges_obj) > 1:
+ doc.addObject("Part::MultiFuse", "union")
union = doc.ActiveObject
- doc.union.Shapes = cp_edges_obj #cp_obj # [doc.Shape005,doc.Shape006]
- if len (cp_edges_obj) < max_geo_admitted:
+ doc.union.Shapes = cp_edges_obj # cp_obj # [doc.Shape005,doc.Shape006]
+ if len(cp_edges_obj) < max_geo_admitted:
doc.recompute()
else:
union = cp_edges_obj[0]
- #sketch.MapMode = "ObjectXZ"
- #sketch.Support = [(doc.Cut,'Face2')]
- #sketch.MapMode = 'FlatFace'
+ # sketch.MapMode = "ObjectXZ"
+ # sketch.Support = [(doc.Cut,'Face2')]
+ # sketch.MapMode = 'FlatFace'
# doc.recompute()
- #Draft.makeSketch([wire],addTo=sketch)
- # points =
- #print(cp_points)
+ # Draft.makeSketch([wire],addTo=sketch)
+ # points =
+ # print(cp_points)
triple = []
- if len (cp_points) > 2:
+ if len(cp_points) > 2:
for p in cp_points:
if p not in triple:
triple.append(p)
- face= Part.Face(Part.makePolygon([p for p in triple], True))
+ face = Part.Face(Part.makePolygon(list(triple), True))
else:
for _e in cp_edges:
if _e.isClosed():
face = Part.Face(Part.Wire(_e))
- #print (triple)
- #plane = Part.Plane(*[p for p in triple])
- #print([p for p in triple])
+ # print (triple)
+ # plane = Part.Plane(*[p for p in triple])
+ # print([p for p in triple])
if create_plane:
- doc.addObject('Part::Feature','Face').Shape=face
+ doc.addObject("Part::Feature", "Face").Shape = face
newface = doc.ActiveObject
- #[App.ActiveDocument.union.Shape.Vertex2.Point, App.ActiveDocument.union.Shape.Vertex5.Point, App.ActiveDocument.union.Shape.Vertex1.Point, ], True))
- #print(plane)
+ # [App.ActiveDocument.union.Shape.Vertex2.Point, App.ActiveDocument.union.Shape.Vertex5.Point, App.ActiveDocument.union.Shape.Vertex1.Point, ], True))
+ # print(plane)
## _makeSketch(plane,wires,addTo=sketch)
- #Draft.makeSketch(wires,addTo=sketch)
- _objs_ = []
+ # Draft.makeSketch(wires,addTo=sketch)
obj_tobd = []
use_workaround_1 = False
use_workaround_2 = False
active_view = FreeCADGui.ActiveDocument.activeView()
rotation_view = active_view.getCameraOrientation()
- top_rotation = FreeCAD.Rotation(0.0,0.0,0.0,1.0)
+ top_rotation = FreeCAD.Rotation(0.0, 0.0, 0.0, 1.0)
if rotation_view != top_rotation and len(union.Shape.Edges) < max_geo_admitted:
use_workaround_1 = True
use_workaround_2 = True
if use_workaround_1:
- FreeCAD.Console.PrintWarning('workaround to avoid issues in Draft.makeSketch from Bottom\n')
- _objs_ = Draft.downgrade(FreeCAD.ActiveDocument.getObject('union'), delete=False)
+ FreeCAD.Console.PrintWarning("workaround to avoid issues in Draft.makeSketch from Bottom\n")
+ Draft.downgrade(FreeCAD.ActiveDocument.getObject("union"), delete=False)
FreeCAD.ActiveDocument.recompute()
- _objs_ = []
obj_tobd.append(FreeCADGui.Selection.getSelection())
- _objs_ = Draft.upgrade(FreeCADGui.Selection.getSelection(), delete=True)
- _objs_ = []
+ Draft.upgrade(FreeCADGui.Selection.getSelection(), delete=True)
FreeCAD.ActiveDocument.recompute()
obj_tobd.append(FreeCADGui.Selection.getSelection())
- _objs_ = Draft.downgrade(FreeCADGui.Selection.getSelection(), delete=True)
+ Draft.downgrade(FreeCADGui.Selection.getSelection(), delete=True)
# print(_objs_)
# FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.ActiveObject)
sel_objs = FreeCADGui.Selection.getSelection()
@@ -572,21 +580,21 @@ def ksu_edges2sketch():
# print(len(sel_objs))
# for o in sel_objs:
# print (o.Label)
- #FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject('union'))
+ # FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject('union'))
# FreeCADGui.runCommand('ksuTools2D2Sketch',0)
if use_draft:
- #Draft.makeSketch(union,addTo=sketch)
+ # Draft.makeSketch(union,addTo=sketch)
if use_workaround_1:
- #FreeCADGui.runCommand('ksuTools2D2Sketch',0)
- Draft.makeSketch(FreeCADGui.Selection.getSelection(),autoconstraints=True) #,addTo=sketch)
+ # FreeCADGui.runCommand('ksuTools2D2Sketch',0)
+ Draft.makeSketch(FreeCADGui.Selection.getSelection(), autoconstraints=True) # ,addTo=sketch)
else:
- Draft.makeSketch(union,autoconstraints=True) #,addTo=sketch)
+ Draft.makeSketch(union, autoconstraints=True) # ,addTo=sketch)
sketch = doc.ActiveObject
p = sketch.Placement
# print(p)
# print(p.Rotation.Axis)
if use_workaround_2 and p.Rotation.Axis.z != 1:
- FreeCAD.Console.PrintWarning('workaround on Axis to avoid issues in Draft.makeSketch\n')
+ FreeCAD.Console.PrintWarning("workaround on Axis to avoid issues in Draft.makeSketch\n")
p.Rotation.Axis.x = 0
p.Rotation.Axis.y = 0
p.Rotation.Axis.z = 1
@@ -597,49 +605,48 @@ def ksu_edges2sketch():
sketch.Label = "Sketch_converted"
else:
for _e in union.Shape.Edges:
- if isinstance(_e.Curve,Part.Line) or isinstance(_e.Curve,Part.LineSegment):
- sketch.addGeometry(P_Line(Base.Vector(_e.firstVertex().Point), Base.Vector(_e.lastVertex().Point)))
- #sketch.addGeometry(_e.Curve)
- sk = doc.ActiveObject
+ if isinstance(_e.Curve, (Part.Line, Part.LineSegment)):
+ sketch.addGeometry(
+ P_Line(Base.Vector(_e.firstVertex().Point), Base.Vector(_e.lastVertex().Point)),
+ )
+ # sketch.addGeometry(_e.Curve)
if attach_sketch:
- sketch.Support = [newface, 'Face1']
- sketch.MapMode = 'FlatFace'
- #sk.Placement = union.Placement
+ sketch.Support = [newface, "Face1"]
+ sketch.MapMode = "FlatFace"
+ # sk.Placement = union.Placement
if remove_shapes:
rmvsubtree([union])
if use_workaround_1:
for o in obj_tobd:
- #print(o)
+ # print(o)
for s in o:
- try:
+ with contextlib.suppress(BaseException):
FreeCAD.ActiveDocument.removeObject(s.Name)
- except:
- pass
for o in sel_objs:
FreeCAD.ActiveDocument.removeObject(o.Name)
if create_plane:
rmvsubtree([newface])
- sketch.MapMode = 'Deactivated'
+ sketch.MapMode = "Deactivated"
# for e in cp_edges:
# sketch.addGeometry(e.Curve, False)
# print ('e added')
- for i in range(0, len(sketch.Geometry)):
- try:
+ for i in range(len(sketch.Geometry)):
+ try:
g = str(sketch.Geometry[i])
- if 'BSpline' in g or 'Ellipse' in g:
+ if "BSpline" in g or "Ellipse" in g:
sketch.exposeInternalGeometry(i)
except:
- #print 'error'
+ # print 'error'
pass
- docG.getObject(sketch.Name).LineColor = (1.00,1.00,1.00)
- docG.getObject(sketch.Name).PointColor = (1.00,1.00,1.00)
- #print(docG.getObject(sketch.Name).PointColor)
+ docG.getObject(sketch.Name).LineColor = (1.00, 1.00, 1.00)
+ docG.getObject(sketch.Name).PointColor = (1.00, 1.00, 1.00)
+ # print(docG.getObject(sketch.Name).PointColor)
lg = len(sketch.Geometry)
if lg == 0:
doc.removeObject(sketch.Name)
docG.getObject(selEdge.ObjectName).Visibility = True
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"info", "All Shapes must be co-planar")
+ QtGui.QMessageBox.information(None, "info", "All Shapes must be co-planar")
doc.abortTransaction()
else:
for s in FreeCADGui.Selection.getSelection():
@@ -650,11 +657,15 @@ def ksu_edges2sketch():
if lg < max_geo_admitted:
doc.recompute()
else:
- print('Select coplanar edge(s) or Face(s) or a single Vertex \nof a coplanar outline to get a corresponding Sketch\n')
+ print(
+ "Select coplanar edge(s) or Face(s) or a single Vertex \nof a coplanar outline to get a corresponding Sketch\n",
+ )
# for ob in FreeCAD.ActiveDocument.Objects:
# FreeCADGui.Selection.removeSelection(ob)
+
+
##
-class Ui_Offset_value(object):
+class Ui_Offset_value:
def setupUi(self, Offset_value):
Offset_value.setObjectName("Offset_value")
Offset_value.resize(292, 177)
@@ -663,7 +674,7 @@ def setupUi(self, Offset_value):
self.buttonBoxLayer = QtWidgets.QDialogButtonBox(Offset_value)
self.buttonBoxLayer.setGeometry(QtCore.QRect(10, 130, 271, 32))
self.buttonBoxLayer.setOrientation(QtCore.Qt.Horizontal)
- self.buttonBoxLayer.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
+ self.buttonBoxLayer.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok)
self.buttonBoxLayer.setObjectName("buttonBoxLayer")
self.gridLayoutWidget = QtWidgets.QWidget(Offset_value)
self.gridLayoutWidget.setGeometry(QtCore.QRect(10, 10, 271, 101))
@@ -675,7 +686,7 @@ def setupUi(self, Offset_value):
self.offset_label.setMinimumSize(QtCore.QSize(0, 0))
self.offset_label.setToolTip("")
self.offset_label.setText(translate("Ui_Offset_value", "Offset [+/- mm]:"))
- self.offset_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
+ self.offset_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter)
self.offset_label.setObjectName("offset_label")
self.gridLayout.addWidget(self.offset_label, 0, 0, 1, 1)
self.lineEdit_offset = QtWidgets.QLineEdit(self.gridLayoutWidget)
@@ -690,12 +701,12 @@ def setupUi(self, Offset_value):
self.checkBox.setChecked(True)
self.checkBox.setObjectName("checkBox")
self.gridLayout.addWidget(self.checkBox, 2, 0, 1, 1)
-
+
self.offset_label_2 = QtWidgets.QLabel(self.gridLayoutWidget)
self.offset_label_2.setMinimumSize(QtCore.QSize(0, 0))
self.offset_label_2.setToolTip("")
self.offset_label_2.setText(translate("Ui_Offset_value", "Offset Y [mm]:"))
- self.offset_label_2.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
+ self.offset_label_2.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter)
self.offset_label_2.setObjectName("offset_label_2")
self.gridLayout.addWidget(self.offset_label_2, 1, 0, 1, 1)
self.lineEdit_offset_2 = QtWidgets.QLineEdit(self.gridLayoutWidget)
@@ -712,16 +723,17 @@ def setupUi(self, Offset_value):
def retranslateUi(self, Offset_value):
pass
+
##
#
# class SMExtrudeCommandClass():
# """Extrude face"""
-#
+#
# def GetResources(self):
# return {'Pixmap' : os.path.join( iconPath , 'SMExtrude.svg') , # the name of a svg file available in the resources
# 'MenuText': "Extend Face" ,
# 'ToolTip' : "Extend a face along normal"}
-class Ui_CDialog(object):
+class Ui_CDialog:
def setupUi(self, CDialog):
CDialog.setObjectName("CDialog")
CDialog.resize(317, 302)
@@ -734,16 +746,24 @@ def setupUi(self, CDialog):
self.buttonBox = QtGui.QDialogButtonBox(CDialog)
self.buttonBox.setGeometry(QtCore.QRect(8, 255, 207, 32))
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
- self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
+ self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.Label_howto = QtGui.QLabel(CDialog)
self.Label_howto.setGeometry(QtCore.QRect(20, 5, 265, 61))
- self.Label_howto.setToolTip(translate("Ui_CDialog", "Select a Sketch and Parameters\n"
-"to constraint the sketch\n"
-"NB the Sketch will be modified!"))
+ self.Label_howto.setToolTip(
+ translate(
+ "Ui_CDialog",
+ "Select a Sketch and Parameters\nto constraint the sketch\nNB the Sketch will be modified!",
+ ),
+ )
self.Label_howto.setStatusTip("")
self.Label_howto.setWhatsThis("")
- self.Label_howto.setText(translate("Ui_CDialog", "Select a Sketch and Parameters to
constrain the sketch.
NB the Sketch will be modified!"))
+ self.Label_howto.setText(
+ translate(
+ "Ui_CDialog",
+ "Select a Sketch and Parameters to
constrain the sketch.
NB the Sketch will be modified!",
+ ),
+ )
self.Label_howto.setObjectName("Label_howto")
self.Constraints = QtGui.QGroupBox(CDialog)
self.Constraints.setGeometry(QtCore.QRect(10, 70, 145, 166))
@@ -760,8 +780,7 @@ def setupUi(self, CDialog):
self.verticalLayout.setObjectName("verticalLayout")
self.all_constraints = QtGui.QRadioButton(self.verticalLayoutWidget)
self.all_constraints.setMinimumSize(QtCore.QSize(92, 64))
- self.all_constraints.setToolTip(translate("Ui_CDialog", "Lock Coincident, Horizontal\n"
-"and Vertical"))
+ self.all_constraints.setToolTip(translate("Ui_CDialog", "Lock Coincident, Horizontal\nand Vertical"))
self.all_constraints.setText("")
self.all_constraints.setIcon(icon)
self.all_constraints.setIconSize(QtCore.QSize(48, 48))
@@ -818,40 +837,38 @@ def setupUi(self, CDialog):
self.rmvXGeo.setText("rmv xtr geo")
self.rmvXGeo.setObjectName("rmvXGeo")
- #self.retranslateUi(CDialog)
+ # self.retranslateUi(CDialog)
### --------------------------------------------------------
- #self.checkBox.setText("rmv xtr geo")
+ # self.checkBox.setText("rmv xtr geo")
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), CDialog.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), CDialog.reject)
QtCore.QMetaObject.connectSlotsByName(CDialog)
-
-
- myiconsize=48
+
+ myiconsize = 48
icon = QtGui.QIcon()
- myicon=os.path.join( ksuWB_icons_path , 'Sketcher_LockCoincident.svg')
+ myicon = os.path.join(ksuWB_icons_path, "Sketcher_LockCoincident.svg")
icon.addPixmap(QtGui.QPixmap(myicon), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.coincident.setIcon(icon)
self.coincident.setIconSize(QtCore.QSize(myiconsize, myiconsize))
self.coincident.setChecked(True)
icon1 = QtGui.QIcon()
- myicon=os.path.join( ksuWB_icons_path , 'Sketcher_LockAll.svg')
+ myicon = os.path.join(ksuWB_icons_path, "Sketcher_LockAll.svg")
icon1.addPixmap(QtGui.QPixmap(myicon), QtGui.QIcon.Normal, QtGui.QIcon.Off)
self.all_constraints.setIcon(icon1)
self.all_constraints.setIconSize(QtCore.QSize(myiconsize, myiconsize))
icond = QtGui.QIcon()
- myicon=os.path.join( ksuWB_icons_path , 'Sketcher_LockAll.svg')
+ myicon = os.path.join(ksuWB_icons_path, "Sketcher_LockAll.svg")
icond.addPixmap(QtGui.QPixmap(myicon), QtGui.QIcon.Normal, QtGui.QIcon.Off)
CDialog.setWindowIcon(icon)
-
# remove question mark from the title bar
CDialog.setWindowFlags(CDialog.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint)
- #self.Label_howto.setText("Select a Sketch and Parameters
to constraint the sketch
NB the Sketch will be modified!")
+ # self.Label_howto.setText("Select a Sketch and Parameters
to constraint the sketch
NB the Sketch will be modified!")
def return_strings(self):
- # Return list of values. It need map with str (self.lineedit.text() will return QString)
+ # Return list of values. It need map with str (self.lineedit.text() will return QString)
return map(str, [self.tolerance.text(), self.all_constraints.isChecked(), self.rmvXGeo.isChecked()])
-
+
# @staticmethod
# def get_data(parent=None):
# #dialog = Ui_CDialog()
@@ -859,74 +876,89 @@ def return_strings(self):
# #dialog = QtGui.QDialog()
# dialog.exec_()
# return dialog.return_strings()
-
+
+
################ ------------------- end CD-ui #############################
+
class ksuTools:
"ksu tools object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'kicad-StepUp-icon.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuTools","ksu Tools") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuTools","Activate the main\nKiCad StepUp Tools Dialog")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "kicad-StepUp-icon.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuTools", "ksu Tools"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuTools", "Activate the main\nKiCad StepUp Tools Dialog"),
+ }
+
def IsActive(self):
- #if FreeCAD.ActiveDocument == None:
+ # if FreeCAD.ActiveDocument == None:
# return False
- #else:
+ # else:
# return True
- #import kicadStepUptools
- import os, sys
+ # import kicadStepUptools
return True
-
+
def Activated(self):
# do something here...
import kicadStepUptools
- reload_lib( kicadStepUptools )
+
+ reload_lib(kicadStepUptools)
kicadStepUptools.KSUWidget.activateWindow()
kicadStepUptools.KSUWidget.show()
kicadStepUptools.KSUWidget.raise_()
- FreeCAD.Console.PrintWarning( 'active :)\n' )
- #import kicadStepUptools
-
-FreeCADGui.addCommand('ksuTools',ksuTools())
+ FreeCAD.Console.PrintWarning("active :)\n")
+ # import kicadStepUptools
+
+
+FreeCADGui.addCommand("ksuTools", ksuTools())
##
+
class ksuToolsContour2Poly:
"ksu tools Shapes Selection to PolyLine Sketch"
-
+
def GetResources(self):
- mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsContour2Poly","ksu tools \'RF PolyLined Sketch\'\nSelection\'s Shapes to PolyLine Sketch")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Sketcher_CreatePolyline-RF.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP(
+ "ksuToolsContour2Poly",
+ "ksu tools 'RF PolyLined Sketch'\nSelection's Shapes to PolyLine Sketch",
+ )
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Sketcher_CreatePolyline-RF.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def __init__(self):
self.obj = None
self.sub = []
self.active = False
def IsActive(self):
- if bool(FreeCADGui.Selection.getSelection()) is False:
- return False
- return True
-
+ return bool(FreeCADGui.Selection.getSelection()) is not False
+
def Activated(self):
- #import segments2poly
- #import wires2poly
+ # import segments2poly
+ # import wires2poly
import Draft
- doc=FreeCAD.ActiveDocument
- docG = FreeCADGui.ActiveDocument
- selEx=FreeCADGui.Selection.getSelectionEx()
- dwglines =[]
- dqd = 0.01 #discretize(QuasiDeflection=d) => gives a list of points with a maximum deflection 'd' to the edge (faster)
+
+ doc = FreeCAD.ActiveDocument
+ selEx = FreeCADGui.Selection.getSelectionEx()
+
class XYline:
def __init__(self, xs, ys, xe, ye):
self.start = [xs, ys]
- self.end = [xe, ye]
- if len (selEx) > 0:
- doc.openTransaction('e2skd')
- if len(selEx)>1:
+ self.end = [xe, ye]
+
+ if len(selEx) > 0:
+ doc.openTransaction("e2skd")
+ if len(selEx) > 1:
mFuseNm = fuse_objs(selEx)
FuseWires = FreeCAD.ActiveDocument.getObject(mFuseNm).Shape.Wires
Vol = FreeCAD.ActiveDocument.getObject(mFuseNm).Shape.Volume
@@ -939,103 +971,116 @@ def __init__(self, xs, ys, xe, ye):
idx2rmv = []
for w in FuseWires:
for ew in w.Edges:
- if 'Line object' in str(ew.Curve):
+ if "Line object" in str(ew.Curve):
foundE = False
- for i,e in enumerate (EdgesContour):
- if (e.Vertexes[0].Point == ew.Vertexes[0].Point) and (e.Vertexes[1].Point == ew.Vertexes[1].Point):
- #if (_Equal(e.start[0], ew.end[0]) and _Equal(e.start[1], ew.end[1])):
+ for i, e in enumerate(EdgesContour):
+ if (e.Vertexes[0].Point == ew.Vertexes[0].Point) and (
+ e.Vertexes[1].Point == ew.Vertexes[1].Point
+ ):
+ # if (_Equal(e.start[0], ew.end[0]) and _Equal(e.start[1], ew.end[1])):
foundE = True
idx2rmv.append(i)
- #print('found edge',i)
- #elif (_Equal(e.start[1], ew.end[0]) and _Equal(e.start[0], ew.end[1])):
- elif (e.Vertexes[1].Point == ew.Vertexes[0].Point) and (e.Vertexes[0].Point == ew.Vertexes[1].Point):
+ # print('found edge',i)
+ # elif (_Equal(e.start[1], ew.end[0]) and _Equal(e.start[0], ew.end[1])):
+ elif (e.Vertexes[1].Point == ew.Vertexes[0].Point) and (
+ e.Vertexes[0].Point == ew.Vertexes[1].Point
+ ):
foundE = True
idx2rmv.append(i)
- #print('found edge',i)
- if foundE == False:
+ # print('found edge',i)
+ if not foundE:
EdgesContour.append(ew)
else:
- EdgesContour.append (ew)
- #print(len(EdgesContour))
- #print(idx2rmv,len(idx2rmv))
+ EdgesContour.append(ew)
+ # print(len(EdgesContour))
+ # print(idx2rmv,len(idx2rmv))
EdgesContourCleaned = []
- for j,e in enumerate (EdgesContour):
+ for j, e in enumerate(EdgesContour):
if j not in idx2rmv:
- EdgesContourCleaned.append (e)
+ EdgesContourCleaned.append(e)
sk = Draft.makeSketch(EdgesContourCleaned, autoconstraints=True)
- sk.Label = 'Pads_Poly'
- if len(selEx)>1:
+ sk.Label = "Pads_Poly"
+ if len(selEx) > 1:
FreeCAD.ActiveDocument.removeObject(mFuseNm)
else:
- FreeCAD.ActiveDocument.addObject('Part::Refine','Refined').Source=FreeCAD.ActiveDocument.getObject(mFuseNm)
+ FreeCAD.ActiveDocument.addObject("Part::Refine", "Refined").Source = FreeCAD.ActiveDocument.getObject(
+ mFuseNm,
+ )
RefName = FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.recompute()
sv0 = Draft.makeShape2DView(FreeCAD.ActiveDocument.getObject(RefName), FreeCAD.Vector(-0.0, -0.0, 1.0))
FreeCAD.ActiveDocument.recompute()
FreeCADGui.Selection.clearSelection()
- FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Name,sv0.Name)
+ FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Name, sv0.Name)
sk = Draft.makeSketch(FreeCADGui.Selection.getSelection(), autoconstraints=True)
- sk.Label = 'Pads_Poly'
+ sk.Label = "Pads_Poly"
if 1:
### Begin command Std_Delete
FreeCAD.ActiveDocument.removeObject(RefName)
FreeCAD.ActiveDocument.removeObject(sv0.Name)
- #FreeCAD.ActiveDocument.recompute()
- if len(selEx)>1:
+ # FreeCAD.ActiveDocument.recompute()
+ if len(selEx) > 1:
FreeCAD.ActiveDocument.removeObject(mFuseNm)
FreeCAD.ActiveDocument.recompute()
- #creating an edge ordered sketch
+ # creating an edge ordered sketch
sv0 = Draft.makeShape2DView(FreeCAD.ActiveDocument.getObject(sk.Name), FreeCAD.Vector(-0.0, -0.0, 1.0))
FreeCAD.ActiveDocument.recompute()
FreeCAD.ActiveDocument.removeObject(sk.Name)
FreeCADGui.Selection.clearSelection()
- FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Name,sv0.Name)
+ FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Name, sv0.Name)
sk = Draft.makeSketch(FreeCADGui.Selection.getSelection(), autoconstraints=True)
- FreeCADGui.ActiveDocument.getObject(sk.Name).LineColor = (1.000,1.000,1.000)
- FreeCADGui.ActiveDocument.getObject(sk.Name).PointColor = (1.000,1.000,1.000)
+ FreeCADGui.ActiveDocument.getObject(sk.Name).LineColor = (1.000, 1.000, 1.000)
+ FreeCADGui.ActiveDocument.getObject(sk.Name).PointColor = (1.000, 1.000, 1.000)
FreeCAD.ActiveDocument.removeObject(sv0.Name)
- sk.Label = 'Pads_Poly'
+ sk.Label = "Pads_Poly"
FreeCAD.ActiveDocument.recompute()
-
-
+
doc.commitTransaction()
- msg=translate(
+ msg = translate(
"ksu",
"PolyLine Contour generated\n\n"
- "For PolyLine Pads, please add \'circles\' inside each closed polyline
")
+ "For PolyLine Pads, please add 'circles' inside each closed polyline
",
+ )
info_msg(msg)
- #stop
- #FreeCAD.ActiveDocument.recompute()
-#
+ # stop
+ # FreeCAD.ActiveDocument.recompute()
+
+
if FreeCAD.GuiUp:
- FreeCADGui.addCommand('ksuToolsContour2Poly',ksuToolsContour2Poly())
+ FreeCADGui.addCommand("ksuToolsContour2Poly", ksuToolsContour2Poly())
+
+
##
class ksuToolsMoveSketch:
"ksu tools MoveSketch"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Sketcher_Move.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsMoveSketch","Move Sketch") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsMoveSketch","ksu Move 2D Sketch")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Sketcher_Move.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsMoveSketch", "Move Sketch"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsMoveSketch", "ksu Move 2D Sketch"),
+ }
+
def IsActive(self):
sel = FreeCADGui.Selection.getSelection()
- if len(sel) == 0:
- return False
- else:
- return True
+ return len(sel) != 0
def Activated(self):
# do something here...
- sel=FreeCADGui.Selection.getSelection()
- if len (sel) == 1:
+ sel = FreeCADGui.Selection.getSelection()
+ if len(sel) == 1:
doc = FreeCAD.ActiveDocument
- if 'Sketcher' in sel[0].TypeId:
+ if "Sketcher" in sel[0].TypeId:
s = doc.getObject(sel[0].Name)
offsetDlg = QtGui.QDialog()
ui = Ui_Offset_value()
ui.setupUi(offsetDlg)
- ui.offset_label.setText(translate("ksu","Select a Sketch and Parameters to
move the sketch.
Offset X:"))
+ ui.offset_label.setText(
+ translate("ksu", "Select a Sketch and Parameters to
move the sketch.
Offset X:"),
+ )
ui.lineEdit_offset.setText("10.0")
ui.offset_label_2.setText("Offset Y [mm]:")
ui.lineEdit_offset_2.setToolTip("Offset Y value [+/- mm]")
@@ -1043,64 +1088,69 @@ def Activated(self):
ui.checkBox.setText("reset Placement")
ui.checkBox.setVisible(True)
ui.checkBox.setChecked(False)
- ui.checkBox.setToolTip("reset Placement of Sketch,\nmoving the internal geometry\nignoring offset imput fields")
- reply=offsetDlg.exec_()
- skip=False
- if reply==1: # ok
+ ui.checkBox.setToolTip(
+ "reset Placement of Sketch,\nmoving the internal geometry\nignoring offset imput fields",
+ )
+ reply = offsetDlg.exec_()
+ skip = False
+ if reply == 1: # ok
if ui.checkBox.isChecked():
- if s.Placement.Rotation == FreeCAD.Rotation(0.0,0.0,0.0,1.0):
- offsetX=s.Placement.Base.x
- offsetY=s.Placement.Base.y
+ if s.Placement.Rotation == FreeCAD.Rotation(0.0, 0.0, 0.0, 1.0):
+ offsetX = s.Placement.Base.x
+ offsetY = s.Placement.Base.y
else:
- #print(s.Placement.Rotation)
- print('available only on Angle (0,0,0)')
- msg="""available only on Angle (0,0,0)"""
+ # print(s.Placement.Rotation)
+ print("available only on Angle (0,0,0)")
+ msg = """available only on Angle (0,0,0)"""
QtGui.QApplication.restoreOverrideCursor()
- QtGui.QMessageBox.information(None,"Info ...",msg)
- skip=True
+ QtGui.QMessageBox.information(None, "Info ...", msg)
+ skip = True
else:
- offsetX=float(ui.lineEdit_offset.text().replace(',','.'))
- offsetY=float(ui.lineEdit_offset_2.text().replace(',','.'))
+ offsetX = float(ui.lineEdit_offset.text().replace(",", "."))
+ offsetY = float(ui.lineEdit_offset_2.text().replace(",", "."))
if not skip:
- doc.openTransaction('moveSk')
+ doc.openTransaction("moveSk")
n = doc.getObject(s.Name).GeometryCount
- mv = []
- for j in range (n):
- mv.append(j)
+ mv = list(range(n))
doc.getObject(s.Name).addMove(mv, FreeCAD.Vector(offsetX, offsetY, 0))
if ui.checkBox.isChecked():
- s.Placement.Base.x=0
- s.Placement.Base.y=0
+ s.Placement.Base.x = 0
+ s.Placement.Base.y = 0
doc.recompute([s])
doc.commitTransaction()
else:
- print('Cancel')
+ print("Cancel")
else:
- print('select a Sketch')
- #doc.recompute(None,True,True)
- #doc.abortTransaction()
+ print("select a Sketch")
+ # doc.recompute(None,True,True)
+ # doc.abortTransaction()
+
+
+FreeCADGui.addCommand("ksuToolsMoveSketch", ksuToolsMoveSketch())
+
-FreeCADGui.addCommand('ksuToolsMoveSketch',ksuToolsMoveSketch())
##
class ksuToolsOffset2D:
"ksu tools Offset2D"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Offset2D.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsOffset2D","Offset 2D") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsOffset2D","ksu Offset 2D object")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Offset2D.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsOffset2D", "Offset 2D"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsOffset2D", "ksu Offset 2D object"),
+ }
+
def IsActive(self):
sel = FreeCADGui.Selection.getSelection()
- if len(sel) == 0:
- return False
- else:
- return True
+ return len(sel) != 0
def Activated(self):
# do something here...
- sel=FreeCADGui.Selection.getSelection()
- if len (sel) == 1:
+ sel = FreeCADGui.Selection.getSelection()
+ if len(sel) == 1:
doc = FreeCAD.ActiveDocument
offsetDlg = QtGui.QDialog()
ui = Ui_Offset_value()
@@ -1108,413 +1158,484 @@ def Activated(self):
ui.lineEdit_offset.setText("-1.0")
ui.offset_label_2.setVisible(False)
ui.lineEdit_offset_2.setVisible(False)
- reply=offsetDlg.exec_()
- if reply==1: # ok
- offset=float(ui.lineEdit_offset.text().replace(',','.'))
- if ui.checkBox.isChecked():
- offset_method = 'Arc'
- else:
- offset_method = 'Intersection'
- doc.openTransaction('off2D')
+ reply = offsetDlg.exec_()
+ if reply == 1: # ok
+ offset = float(ui.lineEdit_offset.text().replace(",", "."))
+ offset_method = "Arc" if ui.checkBox.isChecked() else "Intersection"
+ doc.openTransaction("off2D")
f = doc.addObject("Part::Offset2D", "Offset2D")
- f.Source = sel[0] #some object
+ f.Source = sel[0] # some object
f.Value = offset
- f.Join=offset_method
- doc.ActiveObject.ViewObject.LineColor = (0.00,0.0,1.0)
- doc.ActiveObject.ViewObject.PointColor = (0.00,0.0,1.0)
+ f.Join = offset_method
+ doc.ActiveObject.ViewObject.LineColor = (0.00, 0.0, 1.0)
+ doc.ActiveObject.ViewObject.PointColor = (0.00, 0.0, 1.0)
sel[0].ViewObject.Visibility = False
doc.commitTransaction()
doc.recompute([f])
else:
- print('Cancel')
- #doc.recompute(None,True,True)
- #doc.abortTransaction()
+ print("Cancel")
+ # doc.recompute(None,True,True)
+ # doc.abortTransaction()
+
+
+FreeCADGui.addCommand("ksuToolsOffset2D", ksuToolsOffset2D())
+
-FreeCADGui.addCommand('ksuToolsOffset2D',ksuToolsOffset2D())
##
class ksuToolsExtrude:
"ksu tools Extrude Selection"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsExtrude","ksu tools \'Extrude\'\nExtrude selection")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Part_Extrude.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsExtrude", "ksu tools 'Extrude'\nExtrude selection")
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Part_Extrude.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def __init__(self):
self.obj = None
self.sub = []
self.active = False
def IsActive(self):
- if bool(FreeCADGui.Selection.getSelection()) is False:
- return False
- return True
-
+ return bool(FreeCADGui.Selection.getSelection()) is not False
+
def Activated(self):
- sel = FreeCADGui.Selection.getSelectionEx()[0]
- FreeCADGui.runCommand('Part_Extrude',0)
+ FreeCADGui.Selection.getSelectionEx()[0]
+ FreeCADGui.runCommand("Part_Extrude", 0)
+
if FreeCAD.GuiUp:
- FreeCADGui.addCommand('ksuToolsExtrude',ksuToolsExtrude())
+ FreeCADGui.addCommand("ksuToolsExtrude", ksuToolsExtrude())
##
+
class ksuToolsSkValidate:
"ksu tools Sketcher Validate Selection"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsSkValidate","ksu tools \'Sketcher Validate\'\nValidate selected Sketch")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Sketcher_Validate.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP(
+ "ksuToolsSkValidate",
+ "ksu tools 'Sketcher Validate'\nValidate selected Sketch",
+ )
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Sketcher_Validate.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def __init__(self):
self.obj = None
self.sub = []
self.active = False
def IsActive(self):
- if bool(FreeCADGui.Selection.getSelection()) is False:
- return False
- return True
-
+ return bool(FreeCADGui.Selection.getSelection()) is not False
+
def Activated(self):
- sel = FreeCADGui.Selection.getSelectionEx()[0]
- FreeCADGui.runCommand('Sketcher_ValidateSketch',0)
+ FreeCADGui.Selection.getSelectionEx()[0]
+ FreeCADGui.runCommand("Sketcher_ValidateSketch", 0)
+
if FreeCAD.GuiUp:
- FreeCADGui.addCommand('ksuToolsSkValidate',ksuToolsSkValidate())
+ FreeCADGui.addCommand("ksuToolsSkValidate", ksuToolsSkValidate())
##
+
class ksuToolsOpenBoard:
"ksu tools Open Board object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'importBoard.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsOpenBoard","Load Board") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsOpenBoard","ksu Load KiCad PCB Board and Parts")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "importBoard.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsOpenBoard", "Load Board"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsOpenBoard", "ksu Load KiCad PCB Board and Parts"),
+ }
+
def IsActive(self):
- #if FreeCAD.ActiveDocument == None:
+ # if FreeCAD.ActiveDocument == None:
# return False
- #else:
+ # else:
# return True
- #import kicadStepUptools
+ # import kicadStepUptools
return True
-
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
if reload_Gui:
- reload_lib( kicadStepUptools )
- #from kicadStepUptools import onPushPCB
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
+ reload_lib(kicadStepUptools)
+ # from kicadStepUptools import onPushPCB
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
kicadStepUptools.onLoadBoard()
# ppcb=kicadStepUptools.KSUWidget
# ppcb.onPushPCB()
-
- #onPushPCB()
- #import kicadStepUptools
+
+ # onPushPCB()
+ # import kicadStepUptools
-FreeCADGui.addCommand('ksuToolsOpenBoard',ksuToolsOpenBoard())
+FreeCADGui.addCommand("ksuToolsOpenBoard", ksuToolsOpenBoard())
##
+
class ksuToolsLoadFootprint:
"ksu tools Load Footprint object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'importFP.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsLoadFootprint","Load FootPrint") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsLoadFootprint","ksu Load KiCad PCB FootPrint")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "importFP.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsLoadFootprint", "Load FootPrint"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsLoadFootprint", "ksu Load KiCad PCB FootPrint"),
+ }
+
def IsActive(self):
- #if FreeCAD.ActiveDocument == None:
+ # if FreeCAD.ActiveDocument == None:
# return False
- #else:
+ # else:
# return True
- #import kicadStepUptools
+ # import kicadStepUptools
return True
-
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
- if 1: #reload_Gui:
- reload_lib( kicadStepUptools )
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
+ if 1: # reload_Gui:
+ reload_lib(kicadStepUptools)
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
kicadStepUptools.KSUWidget.activateWindow()
kicadStepUptools.KSUWidget.show()
kicadStepUptools.KSUWidget.raise_()
kicadStepUptools.onLoadFootprint()
-FreeCADGui.addCommand('ksuToolsLoadFootprint',ksuToolsLoadFootprint())
+
+FreeCADGui.addCommand("ksuToolsLoadFootprint", ksuToolsLoadFootprint())
##
+
class ksuToolsExportModel:
"ksu tools Export Model to KiCad object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'export3DModel.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsExportModel","Export 3D Model") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsExportModel","ksu Export 3D Model to KiCad")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "export3DModel.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsExportModel", "Export 3D Model"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsExportModel", "ksu Export 3D Model to KiCad"),
+ }
+
def IsActive(self):
- #if FreeCAD.ActiveDocument == None:
+ # if FreeCAD.ActiveDocument == None:
# return False
- #else:
+ # else:
# return True
- #import kicadStepUptools
+ # import kicadStepUptools
return True
-
+
def Activated(self):
# do something here...
# import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
- #if reload_Gui:
+ # if reload_Gui:
# reload_lib( kicadStepUptools )
- #from kicadStepUptools import onPushPCB
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
- ##evaluate to read cfg and get materials value???
- ##or made something as in load board
- #ini_content=kicadStepUptools.cfg_read_all()
+ # from kicadStepUptools import onPushPCB
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
+ ##evaluate to read cfg and get materials value???
+ ##or made something as in load board
+ # ini_content=kicadStepUptools.cfg_read_all()
if FreeCAD.ActiveDocument.FileName == "":
msg = translate("Save", "Please save your job file before exporting.")
QtGui.QApplication.restoreOverrideCursor()
- QtGui.QMessageBox.information(None,translate("Save", "Info ..."),msg)
+ QtGui.QMessageBox.information(None, translate("Save", "Info ..."), msg)
FreeCADGui.SendMsgToActiveView(translate("Save", "Save"))
-
+
from kicadStepUptools import routineScaleVRML
+
if reload_Gui:
- reload_lib( kicadStepUptools )
+ reload_lib(kicadStepUptools)
routineScaleVRML()
## kicadStepUptools.routineScaleVRML()
- #kicadStepUptools.Ui_DockWidget.onCfg()
+ # kicadStepUptools.Ui_DockWidget.onCfg()
# ppcb=kicadStepUptools.KSUWidget
# ppcb.onPushPCB()
-
- #onPushPCB()
- #import kicadStepUptools
-FreeCADGui.addCommand('ksuToolsExportModel',ksuToolsExportModel())
+ # onPushPCB()
+ # import kicadStepUptools
+
+
+FreeCADGui.addCommand("ksuToolsExportModel", ksuToolsExportModel())
##
+
class ksuToolsImport3DStep:
"ksu tools Import 3D Step object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'add_block_y.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsImport3DStep","Import 3D STEP") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsImport3DStep","ksu Import 3D STEP Model")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "add_block_y.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsImport3DStep", "Import 3D STEP"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsImport3DStep", "ksu Import 3D STEP Model"),
+ }
+
def IsActive(self):
- #if FreeCAD.ActiveDocument == None:
+ # if FreeCAD.ActiveDocument == None:
# return False
- #else:
+ # else:
# return True
- #import kicadStepUptools
+ # import kicadStepUptools
return True
-
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
if reload_Gui:
- reload_lib( kicadStepUptools )
- #from kicadStepUptools import onPushPCB
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
+ reload_lib(kicadStepUptools)
+ # from kicadStepUptools import onPushPCB
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
kicadStepUptools.Import3DModelF()
-FreeCADGui.addCommand('ksuToolsImport3DStep',ksuToolsImport3DStep())
+
+FreeCADGui.addCommand("ksuToolsImport3DStep", ksuToolsImport3DStep())
##
+
class ksuToolsExport3DStep:
"ksu tools Export 3D to Step object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'export3DStep.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsExport3DStep","Export 3D to STEP") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsExport3DStep","ksu Export selected objects to STEP Model")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "export3DStep.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsExport3DStep", "Export 3D to STEP"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsExport3DStep", "ksu Export selected objects to STEP Model"),
+ }
+
def IsActive(self):
- #if FreeCAD.ActiveDocument == None:
+ # if FreeCAD.ActiveDocument == None:
# return False
- #else:
+ # else:
# return True
- #import kicadStepUptools
+ # import kicadStepUptools
return True
-
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
if reload_Gui:
- reload_lib( kicadStepUptools )
- #from kicadStepUptools import onPushPCB
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
+ reload_lib(kicadStepUptools)
+ # from kicadStepUptools import onPushPCB
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
kicadStepUptools.Export3DStepF()
-FreeCADGui.addCommand('ksuToolsExport3DStep',ksuToolsExport3DStep())
+
+FreeCADGui.addCommand("ksuToolsExport3DStep", ksuToolsExport3DStep())
##
+
class ksuToolsMakeUnion:
"ksu tools Make a Union object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'fusion.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsMakeUnion","Make Union") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsMakeUnion","ksu Make a Union of selected objects")}
-
+ return {
+ "Pixmap": os.path.join(ksuWB_icons_path, "fusion.svg"), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsMakeUnion", "Make Union"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsMakeUnion", "ksu Make a Union of selected objects"),
+ }
+
def IsActive(self):
- #if FreeCAD.ActiveDocument == None:
+ # if FreeCAD.ActiveDocument == None:
# return False
- #else:
+ # else:
# return True
- #import kicadStepUptools
+ # import kicadStepUptools
return True
-
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
if reload_Gui:
- reload_lib( kicadStepUptools )
- #from kicadStepUptools import onPushPCB
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
+ reload_lib(kicadStepUptools)
+ # from kicadStepUptools import onPushPCB
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
kicadStepUptools.group_part_union()
-FreeCADGui.addCommand('ksuToolsMakeUnion',ksuToolsMakeUnion())
+
+FreeCADGui.addCommand("ksuToolsMakeUnion", ksuToolsMakeUnion())
##
+
class ksuToolsMakeCompound:
"ksu tools Make a Union object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'compound.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsMakeCompound","Make Compound") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsMakeCompound","ksu Make a Compound of selected objects")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "compound.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsMakeCompound", "Make Compound"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsMakeCompound", "ksu Make a Compound of selected objects"),
+ }
+
def IsActive(self):
- #if FreeCAD.ActiveDocument == None:
+ # if FreeCAD.ActiveDocument == None:
# return False
- #else:
+ # else:
# return True
- #import kicadStepUptools
+ # import kicadStepUptools
return True
-
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
if reload_Gui:
- reload_lib( kicadStepUptools )
- #from kicadStepUptools import onPushPCB
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
+ reload_lib(kicadStepUptools)
+ # from kicadStepUptools import onPushPCB
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
kicadStepUptools.group_part()
-FreeCADGui.addCommand('ksuToolsMakeCompound',ksuToolsMakeCompound())
+
+FreeCADGui.addCommand("ksuToolsMakeCompound", ksuToolsMakeCompound())
##
+
class ksuToolsPushPCB:
"ksu tools Push Sketch object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Sketcher_Rectangle.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsPushPCB","Push Sketch to PCB") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsPushPCB","ksu Push Sketch to PCB Edge")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Sketcher_Rectangle.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsPushPCB", "Push Sketch to PCB"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsPushPCB", "ksu Push Sketch to PCB Edge"),
+ }
+
def IsActive(self):
- #if FreeCAD.ActiveDocument == None:
+ # if FreeCAD.ActiveDocument == None:
# return False
- #else:
+ # else:
# return True
- #import kicadStepUptools
+ # import kicadStepUptools
return True
-
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
if reload_Gui:
- reload_lib( kicadStepUptools )
- #from kicadStepUptools import onPushPCB
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
+ reload_lib(kicadStepUptools)
+ # from kicadStepUptools import onPushPCB
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
sel = FreeCADGui.Selection.getSelection()
- if len (sel) ==1:
- if 'Sketcher' in sel[0].TypeId or 'Shape2DView' in sel[0].Name:
- #FreeCADGui.ActiveDocument.ActiveView.setCameraOrientation(sel[0].Placement.Rotation)
- #FreeCAD.ActiveDocument.recompute(None,True,True)
- FreeCAD.ActiveDocument.openTransaction('pushpcb')
+ if len(sel) == 1:
+ if "Sketcher" in sel[0].TypeId or "Shape2DView" in sel[0].Name:
+ # FreeCADGui.ActiveDocument.ActiveView.setCameraOrientation(sel[0].Placement.Rotation)
+ # FreeCAD.ActiveDocument.recompute(None,True,True)
+ FreeCAD.ActiveDocument.openTransaction("pushpcb")
from pivy import coin
- print('getting camera view')
+
+ print("getting camera view")
pcam = FreeCADGui.ActiveDocument.ActiveView.getCamera()
- #
sketch = sel[0]
rot = sketch.getGlobalPlacement().Rotation
cam = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
cam.orientation.setValue(coin.SbVec3f(rot.Axis.x, rot.Axis.y, rot.Axis.z), rot.Angle)
FreeCADGui.ActiveDocument.ActiveView.fitAll()
- print('evaluate to recompute')
+ print("evaluate to recompute")
## s = sel[0].Shape
## sk = Draft.make_sketch(s.Edges, autoconstraints=True)
- #print(sel[0].InListRecursive, sel[0].Label)
+ # print(sel[0].InListRecursive, sel[0].Label)
for o in sel[0].InListRecursive:
- if 'PartDesign::Body' in o.TypeId: #issue if sketch is in Body
- FreeCADGui.runCommand('ksuTools2D2Sketch',0)
- #FreeCADGui.Selection.removeSelection(sel[0])
+ if "PartDesign::Body" in o.TypeId: # issue if sketch is in Body
+ FreeCADGui.runCommand("ksuTools2D2Sketch", 0)
+ # FreeCADGui.Selection.removeSelection(sel[0])
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(FreeCAD.activeDocument().ActiveObject)
sel = FreeCADGui.Selection.getSelection()
- lbl=sketch.Label
+ lbl = sketch.Label
sketch = sel[0]
- sketch.Label=lbl
- #stop
+ sketch.Label = lbl
+ # stop
break
- if 'Sketcher' in sel[0].TypeId:
+ if "Sketcher" in sel[0].TypeId:
kicadStepUptools.sanitizeSketch(sketch.Name)
FreeCAD.ActiveDocument.recompute()
if 0:
# sk = Draft.make_sketch(sketch, autoconstraints=True)
- sk = Draft.make_sketch(sketch, autoconstraints=False) #, avoidredundant=False)
+ Draft.make_sketch(sketch, autoconstraints=False) # , avoidredundant=False)
sk_obj = FreeCAD.ActiveDocument.ActiveObject
FreeCADGui.ActiveDocument.getObject(sk_obj.Name).AvoidRedundant = False
else:
doc = FreeCAD.ActiveDocument
FreeCADGui.Selection.clearSelection()
- if 'Shape2DView' in sel[0].Name:
- shp=FreeCAD.ActiveDocument.getObject(sketch.Name).Shape
+ if "Shape2DView" in sel[0].Name:
+ shp = FreeCAD.ActiveDocument.getObject(sketch.Name).Shape
Part.show(shp)
- shp=FreeCAD.ActiveDocument.ActiveObject
- FreeCADGui.Selection.addSelection(doc.Name,shp.Name)
- FreeCAD.ActiveDocument.ActiveObject.ViewObject.Visibility=False
+ shp = FreeCAD.ActiveDocument.ActiveObject
+ FreeCADGui.Selection.addSelection(doc.Name, shp.Name)
+ FreeCAD.ActiveDocument.ActiveObject.ViewObject.Visibility = False
else:
- FreeCADGui.Selection.addSelection(doc.Name,sketch.Name)
- FreeCADGui.runCommand('Std_Copy',0)
- FreeCADGui.runCommand('Std_Paste',0)
+ FreeCADGui.Selection.addSelection(doc.Name, sketch.Name)
+ FreeCADGui.runCommand("Std_Copy", 0)
+ FreeCADGui.runCommand("Std_Paste", 0)
sk_obj = FreeCAD.ActiveDocument.ActiveObject
- if 'Shape2DView' in sel[0].Name:
- sk = Draft.make_sketch(sk_obj, autoconstraints=False) #, avoidredundant=False)
- FreeCAD.ActiveDocument.getObject(sk_obj.Name).ViewObject.Visibility=False
+ if "Shape2DView" in sel[0].Name:
+ Draft.make_sketch(sk_obj, autoconstraints=False) # , avoidredundant=False)
+ FreeCAD.ActiveDocument.getObject(sk_obj.Name).ViewObject.Visibility = False
sk_obj = FreeCAD.ActiveDocument.ActiveObject
FreeCADGui.ActiveDocument.getObject(sk_obj.Name).AvoidRedundant = False
# FreeCAD.ActiveDocument.getObject(sk_obj.Name).purgeTouched() #mark to NOT recompute object
# App.ActiveDocument.Dwgs_Sketch.purgeTouched()
- else: # a sketch that is already sanitized
+ else: # a sketch that is already sanitized
# sk = Draft.make_sketch(sketch, autoconstraints=True)
# FreeCAD.ActiveDocument.getObject(sk_obj.Name).ViewObject.Visibility=False
# sk_obj = FreeCAD.ActiveDocument.ActiveObject
FreeCADGui.ActiveDocument.getObject(sk_obj.Name).Autoconstraints = True
FreeCADGui.ActiveDocument.getObject(sk_obj.Name).AvoidRedundant = True
-
+
FreeCAD.ActiveDocument.recompute()
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(sk_obj)
@@ -1524,104 +1645,116 @@ def Activated(self):
# print('evaluate to recompute')
# FreeCAD.ActiveDocument.recompute()
# print(sel[0].Label)
-
+
# tol = 0.0001
# constr = 'coincident'
# add_constraints(sk_obj.Name, tol, constr)
# FreeCAD.ActiveDocument.recompute(None,True,True)
- FreeCAD.ActiveDocument.recompute() #we must recompute first
+ FreeCAD.ActiveDocument.recompute() # we must recompute first
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(sk_obj)
kicadStepUptools.PushPCB()
FreeCAD.ActiveDocument.removeObject(sk_obj.Name)
- print('restoring cam view')
+ print("restoring cam view")
FreeCADGui.ActiveDocument.ActiveView.setCamera(pcam)
- print('restoring sk visibility')
+ print("restoring sk visibility")
sel[0].ViewObject.Visibility = True
# FreeCADGui.ActiveDocument.ActiveView.setCamera(pcam)
FreeCAD.ActiveDocument.commitTransaction()
- FreeCADGui.runCommand('Std_Undo',0)
+ FreeCADGui.runCommand("Std_Undo", 0)
else:
- msg="""select one Sketch to be pushed to kicad board!"""
+ msg = """select one Sketch to be pushed to kicad board!"""
FreeCAD.Console.PrintError(msg)
- FreeCAD.Console.PrintWarning('\n')
+ FreeCAD.Console.PrintWarning("\n")
kicadStepUptools.say_warning(msg)
else:
- msg="""select one Sketch or a Shape2DView to be pushed to kicad board!"""
+ msg = """select one Sketch or a Shape2DView to be pushed to kicad board!"""
FreeCAD.Console.PrintError(msg)
- FreeCAD.Console.PrintWarning('\n')
+ FreeCAD.Console.PrintWarning("\n")
kicadStepUptools.say_warning(msg)
# ppcb=kicadStepUptools.KSUWidget
# ppcb.onPushPCB()
-
- #onPushPCB()
- #import kicadStepUptools
+
+ # onPushPCB()
+ # import kicadStepUptools
+
+
+FreeCADGui.addCommand("ksuToolsPushPCB", ksuToolsPushPCB())
-FreeCADGui.addCommand('ksuToolsPushPCB',ksuToolsPushPCB())
##
class ksuToolsPullPCB:
"ksu tools Pull Sketch object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Sketcher_Pull.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsPullPCB","Pull Sketch from PCB") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsPullPCB","ksu Pull Sketch from PCB Edge")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Sketcher_Pull.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsPullPCB", "Pull Sketch from PCB"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsPullPCB", "ksu Pull Sketch from PCB Edge"),
+ }
+
def IsActive(self):
- #if FreeCAD.ActiveDocument == None:
+ # if FreeCAD.ActiveDocument == None:
# return False
- #else:
+ # else:
# return True
- #import kicadStepUptools
+ # import kicadStepUptools
return True
-
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
if reload_Gui:
- reload_lib( kicadStepUptools )
- #from kicadStepUptools import onPushPCB
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
+ reload_lib(kicadStepUptools)
+ # from kicadStepUptools import onPushPCB
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
kicadStepUptools.PullPCB()
- #FreeCAD.ActiveDocument.commitTransaction()
+ # FreeCAD.ActiveDocument.commitTransaction()
# ppcb=kicadStepUptools.KSUWidget
# ppcb.onPushPCB()
-
- #onPushPCB()
- #import kicadStepUptools
+
+ # onPushPCB()
+ # import kicadStepUptools
-FreeCADGui.addCommand('ksuToolsPullPCB',ksuToolsPullPCB())
+FreeCADGui.addCommand("ksuToolsPullPCB", ksuToolsPullPCB())
##
+
class ksuToolsPushMoved:
"ksu tools Push 3D moved model"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'PushMoved.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsPushMoved","Push 3D moved model(s) to PCB") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsPushMoved","ksu Push 3D moved model(s) to PCB")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "PushMoved.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsPushMoved", "Push 3D moved model(s) to PCB"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsPushMoved", "ksu Push 3D moved model(s) to PCB"),
+ }
+
def IsActive(self):
- if FreeCAD.ActiveDocument == None:
- return False
- else:
- return True
- #import kicadStepUptools
- #return True
-
+ return FreeCAD.ActiveDocument is not None
+ # import kicadStepUptools
+ # return True
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
if reload_Gui:
- reload_lib( kicadStepUptools )
- #from kicadStepUptools import onPushPCB
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
+ reload_lib(kicadStepUptools)
+ # from kicadStepUptools import onPushPCB
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
# doc=FreeCAD.ActiveDocument
# doc.openTransaction('push3D')
# this cannot be undone!
@@ -1629,76 +1762,91 @@ def Activated(self):
# doc.commitTransaction()
# ppcb=kicadStepUptools.KSUWidget
# ppcb.onPushPCB()
-
- #onPushPCB()
- #import kicadStepUptools
-FreeCADGui.addCommand('ksuToolsPushMoved',ksuToolsPushMoved())
+ # onPushPCB()
+ # import kicadStepUptools
+
+
+FreeCADGui.addCommand("ksuToolsPushMoved", ksuToolsPushMoved())
+
+
##
class ksuToolsPullMoved:
"ksu tools Pull 3D model placement from PCB"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'PullMoved.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsPullMoved","Pull 3D model(s) placement from PCB") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsPullMoved","ksu Pull 3D model(s) placement from PCB")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "PullMoved.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsPullMoved", "Pull 3D model(s) placement from PCB"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsPullMoved", "ksu Pull 3D model(s) placement from PCB"),
+ }
+
def IsActive(self):
- if FreeCAD.ActiveDocument == None:
- return False
- else:
- return True
- #import kicadStepUptools
- #return True
-
+ return FreeCAD.ActiveDocument is not None
+ # import kicadStepUptools
+ # return True
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
if reload_Gui:
- reload_lib( kicadStepUptools )
- #from kicadStepUptools import onPushPCB
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
- doc=FreeCAD.ActiveDocument
- doc.openTransaction('pull3D')
+ reload_lib(kicadStepUptools)
+ # from kicadStepUptools import onPushPCB
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
+ doc = FreeCAD.ActiveDocument
+ doc.openTransaction("pull3D")
kicadStepUptools.PullMoved()
doc.commitTransaction()
# ppcb=kicadStepUptools.KSUWidget
# ppcb.onPushPCB()
- #onPushPCB()
- #import kicadStepUptools
+ # onPushPCB()
+ # import kicadStepUptools
+
+
+FreeCADGui.addCommand("ksuToolsPullMoved", ksuToolsPullMoved())
+
-FreeCADGui.addCommand('ksuToolsPullMoved',ksuToolsPullMoved())
##
class ksuAsm2Part:
"ksu tools Push/Pull 3D moved model"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Assembly_To_Part.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuAsm2Part","Convert an Assembly (A3) to Part hierarchy") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuAsm2Part","ksu Convert an Assembly (A3) to Part hierarchy")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Assembly_To_Part.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuAsm2Part", "Convert an Assembly (A3) to Part hierarchy"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuAsm2Part", "ksu Convert an Assembly (A3) to Part hierarchy"),
+ }
+
def IsActive(self):
import FreeCADGui
- #if a3:
- if 'LinkView' in dir(FreeCADGui): #pre a3 Link3 merge
- return True
- else:
- return False
-
+
+ # if a3:
+ return "LinkView" in dir(FreeCADGui) # pre a3 Link3 merge
+
def Activated(self):
# do something here...
# import kicadStepUptools
# if reload_Gui:
# reload_lib( kicadStepUptools )
- #from kicadStepUptools import onPushPCB
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
- #kicadStepUptools.Asm2Part()
- #Asm2Part()
- import FreeCAD, FreeCADGui, Part
- def Asm2Part(parentObj=None,doc=None,subname=''):
+ # from kicadStepUptools import onPushPCB
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
+ # kicadStepUptools.Asm2Part()
+ # Asm2Part()
+ import FreeCAD
+ import FreeCADGui
+ import Part
+
+ def Asm2Part(parentObj=None, doc=None, subname=""):
if doc is None:
# 'doc' allows you to copy object into another document.
# If not give, then use the current document.
@@ -1706,17 +1854,17 @@ def Asm2Part(parentObj=None,doc=None,subname=''):
if not parentObj:
# If no object is given, then obtain selection from all opened document
parentObj = []
- for sel in FreeCADGui.Selection.getSelectionEx('*'):
+ for sel in FreeCADGui.Selection.getSelectionEx("*"):
parentObj.append(sel.Object)
if not parentObj:
- return
- if isinstance(parentObj,(tuple,list)):
+ return None
+ if isinstance(parentObj, (tuple, list)):
if len(parentObj) == 1:
- copy = Asm2Part(parentObj[0],doc)
+ copy = Asm2Part(parentObj[0], doc)
else:
- part = doc.addObject('App::Part','Part')
+ part = doc.addObject("App::Part", "Part")
for o in parentObj:
- copy = Asm2Part(o,doc)
+ copy = Asm2Part(o, doc)
if copy:
part.addObject(copy)
copy = part
@@ -1724,57 +1872,58 @@ def Asm2Part(parentObj=None,doc=None,subname=''):
FreeCADGui.SendMsgToActiveView("ViewFit")
copy.recompute(True)
return copy
-
- obj,matrix = parentObj.getSubObject(subname,1,FreeCAD.Matrix(),not subname)
+
+ obj, matrix = parentObj.getSubObject(subname, 1, FreeCAD.Matrix(), not subname)
if not obj:
- return
+ return None
# getSubObjects() is the API for getting child of a group. It returns a list
# of subnames, and the subname inside may contain more than one levels of
# hierarchy. Assembly uses this API to skip hierarchy to PartGroup.
subs = obj.getSubObjects()
if not subs:
# Non group object will return empty subs
- shape = Part.getShape(obj,transform=False)
+ shape = Part.getShape(obj, transform=False)
if shape.isNull():
- return
- shape.transformShape(matrix,False,True)
- copy = doc.addObject('Part::Feature',obj.Name)
+ return None
+ shape.transformShape(matrix, False, True)
+ copy = doc.addObject("Part::Feature", obj.Name)
copy.Label = obj.Label
copy.Shape = shape
- if hasattr (copy.ViewObject,"mapShapeColors"): # available on asm3 branch
+ if hasattr(copy.ViewObject, "mapShapeColors"): # available on asm3 branch
copy.ViewObject.mapShapeColors(obj.Document)
return copy
-
- part = doc.addObject('App::Part',obj.Name)
+
+ part = doc.addObject("App::Part", obj.Name)
part.Label = obj.Label
part.Placement = FreeCAD.Placement(matrix)
for sub in subs:
- sobj,parent,childName,_ = obj.resolve(sub)
+ sobj, parent, childName, _ = obj.resolve(sub)
if not sobj:
continue
- copy = Asm2Part(obj,doc,sub)
+ copy = Asm2Part(obj, doc, sub)
if not copy:
continue
vis = parent.isElementVisible(childName)
if vis < 0:
copy.Visibility = sobj.Visibility
else:
- copy.Visibility = vis>0
+ copy.Visibility = vis > 0
part.addObject(copy)
return part
- CopyOnNewDoc=True
+
+ CopyOnNewDoc = True
sel = FreeCADGui.Selection.getSelectionEx()
if len(sel) == 1:
- if 'App::LinkGroup' in sel[0].Object.TypeId:
+ if "App::LinkGroup" in sel[0].Object.TypeId:
if CopyOnNewDoc:
- doc_base=FreeCAD.ActiveDocument
+ doc_base = FreeCAD.ActiveDocument
doc1 = FreeCAD.newDocument(doc_base.Name)
doc1_Name = FreeCAD.ActiveDocument.Name
FreeCAD.setActiveDocument(doc_base.Name)
- #sel = FreeCADGui.Selection.getSelectionEx()
- parentObj=[]
+ # sel = FreeCADGui.Selection.getSelectionEx()
+ parentObj = []
parentObj.append(sel[0].Object)
- Asm2Part(parentObj,doc1)
+ Asm2Part(parentObj, doc1)
FreeCAD.setActiveDocument(doc1_Name)
else:
Asm2Part()
@@ -1782,129 +1931,151 @@ def Asm2Part(parentObj=None,doc=None,subname=''):
FreeCADGui.SendMsgToActiveView("ViewFit")
else:
FreeCAD.Console.PrintWarning("select one Assembly to convert it to Part hierarchy")
- FreeCAD.Console.PrintWarning('\n')
- msg="""select one Assembly to convert it to Part hierarchy"""
- msg1="Warning ..."
+ FreeCAD.Console.PrintWarning("\n")
+ msg = """select one Assembly to convert it to Part hierarchy"""
+ msg1 = "Warning ..."
QtGui.QApplication.restoreOverrideCursor()
- #RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning,
- msg1,
- msg)
+ # RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
+ diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning, msg1, msg)
diag.setWindowModality(QtCore.Qt.ApplicationModal)
diag.exec_()
else:
FreeCAD.Console.PrintWarning("select one Assembly to convert it to Part hierarchy")
- FreeCAD.Console.PrintWarning('\n')
- msg="""select one Assembly to convert it to Part hierarchy"""
- msg1="Warning ..."
+ FreeCAD.Console.PrintWarning("\n")
+ msg = """select one Assembly to convert it to Part hierarchy"""
+ msg1 = "Warning ..."
QtGui.QApplication.restoreOverrideCursor()
- #RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning,
- msg1,
- msg)
+ # RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
+ diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning, msg1, msg)
diag.setWindowModality(QtCore.Qt.ApplicationModal)
diag.exec_()
-FreeCADGui.addCommand('ksuAsm2Part',ksuAsm2Part())
+
+FreeCADGui.addCommand("ksuAsm2Part", ksuAsm2Part())
+
##
class ksuToolsSync3DModels:
"ksu tools Push/Pull 3D moved model"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Sync3Dmodels.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsSync3DModels","Sync 3D model(s) Ref & TimeStamps with PCB") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsSync3DModels","ksu Sync 3D model(s) Ref & TimeStamps\nof the Selected 3D model with KiCad PCB")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Sync3Dmodels.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsSync3DModels", "Sync 3D model(s) Ref & TimeStamps with PCB"),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "ksuToolsSync3DModels",
+ "ksu Sync 3D model(s) Ref & TimeStamps\nof the Selected 3D model with KiCad PCB",
+ ),
+ }
+
def IsActive(self):
- #if FreeCAD.ActiveDocument == None:
+ # if FreeCAD.ActiveDocument == None:
# return False
- #else:
+ # else:
# return True
- #import kicadStepUptools
+ # import kicadStepUptools
return True
-
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
if reload_Gui:
- reload_lib( kicadStepUptools )
- #from kicadStepUptools import onPushPCB
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
+ reload_lib(kicadStepUptools)
+ # from kicadStepUptools import onPushPCB
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
kicadStepUptools.Sync3DModel()
# ppcb=kicadStepUptools.KSUWidget
# ppcb.onPushPCB()
-
- #onPushPCB()
- #import kicadStepUptools
-FreeCADGui.addCommand('ksuToolsSync3DModels',ksuToolsSync3DModels())
+ # onPushPCB()
+ # import kicadStepUptools
+
+
+FreeCADGui.addCommand("ksuToolsSync3DModels", ksuToolsSync3DModels())
+
+
##
##
class ksuToolsGeneratePositions:
"ksu tools Generate 3D models Positions"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'File_Positions.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsGeneratePositions","tools Generate 3D models Positions") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsGeneratePositions","ksu Generate 3D models Positions\nData for Active Document\n[MCAD Synchronize]")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "File_Positions.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsGeneratePositions", "tools Generate 3D models Positions"),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "ksuToolsGeneratePositions",
+ "ksu Generate 3D models Positions\nData for Active Document\n[MCAD Synchronize]",
+ ),
+ }
+
def IsActive(self):
- if FreeCAD.ActiveDocument is None:
- return False
- #else:
- # return True
- #import kicadStepUptools
- return True
-
+ return FreeCAD.ActiveDocument is not None
+
def Activated(self):
# do something here...
- #import kicadStepUptools
- #if reload_Gui:
+ # import kicadStepUptools
+ # if reload_Gui:
# reload_lib( kicadStepUptools )
- import exchangePositions;reload_lib(exchangePositions)
+ import exchangePositions
+
+ reload_lib(exchangePositions)
exchangePositions.expPos()
-
-FreeCADGui.addCommand('ksuToolsGeneratePositions',ksuToolsGeneratePositions())
+
+FreeCADGui.addCommand("ksuToolsGeneratePositions", ksuToolsGeneratePositions())
+
+
##
class ksuToolsComparePositions:
"ksu tools Compare 3D models Positions"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Compare_Positions.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsComparePositions","tools Compare 3D models Positions") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsComparePositions","ksu Compare 3D models Positions\nData with the Active Document\n[MCAD Synchronize]")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Compare_Positions.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsComparePositions", "tools Compare 3D models Positions"),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "ksuToolsComparePositions",
+ "ksu Compare 3D models Positions\nData with the Active Document\n[MCAD Synchronize]",
+ ),
+ }
+
def IsActive(self):
- if FreeCAD.ActiveDocument is None:
- return False
- #else:
- # return True
- #import kicadStepUptools
- return True
-
+ return FreeCAD.ActiveDocument is not None
+
def Activated(self):
# do something here...
- import exchangePositions;reload_lib(exchangePositions)
+ import exchangePositions
+
+ reload_lib(exchangePositions)
exchangePositions.cmpPos()
-
-FreeCADGui.addCommand('ksuToolsComparePositions',ksuToolsComparePositions())
+
+FreeCADGui.addCommand("ksuToolsComparePositions", ksuToolsComparePositions())
##
# class ksuToolsEdit:
# "ksu tools Editor object"
-#
+#
# def GetResources(self):
# return {'Pixmap' : os.path.join( ksuWB_icons_path , 'edit.svg') , # the name of a svg file available in the resources
# 'MenuText': "ksu Edit parameters" ,
# 'ToolTip' : "ksu View Config Parameters"}
-#
+#
# def IsActive(self):
# return True
-#
+#
# def Activated(self):
# # do something here...
# import kicadStepUptools
@@ -1914,50 +2085,61 @@ def Activated(self):
# reload( kicadStepUptools )
# FreeCAD.Console.PrintWarning( 'active :)\n' )
# kicadStepUptools.view_cfg()
-#
+#
# FreeCADGui.addCommand('ksuToolsEdit',ksuToolsEdit())
##
+
class ksuToolsCollisions:
"ksu tools Check Collisions object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'collisions.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsCollisions","Check Collisions") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsCollisions","ksu Check Collisions and Interferences")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "collisions.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsCollisions", "Check Collisions"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsCollisions", "ksu Check Collisions and Interferences"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
if reload_Gui:
- reload_lib( kicadStepUptools )
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
- FreeCAD.ActiveDocument.openTransaction('collisions')
+ reload_lib(kicadStepUptools)
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
+ FreeCAD.ActiveDocument.openTransaction("collisions")
kicadStepUptools.routineCollisions()
FreeCAD.ActiveDocument.commitTransaction()
-FreeCADGui.addCommand('ksuToolsCollisions',ksuToolsCollisions())
+
+FreeCADGui.addCommand("ksuToolsCollisions", ksuToolsCollisions())
##
+
class ksuTools3D2D:
"ksu tools 3D to 2D object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , '3Dto2D.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuTools3D2D","3D to 2D") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuTools3D2D","ksu 3D object to 2D projection")}
-
+ return {
+ "Pixmap": os.path.join(ksuWB_icons_path, "3Dto2D.svg"), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuTools3D2D", "3D to 2D"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuTools3D2D", "ksu 3D object to 2D projection"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
- FreeCAD.Console.PrintMessage('projecting the selected object to a 2D shape in the document\n')
+ FreeCAD.Console.PrintMessage("projecting the selected object to a 2D shape in the document\n")
faces = []
objs = []
if FreeCAD.ActiveDocument is not None:
@@ -1968,226 +2150,258 @@ def Activated(self):
objs.append(s.Object)
for e in s.SubElementNames:
if "Face" in e:
- faces.append(int(e[4:])-1)
- #print(objs,faces)
+ faces.append(int(e[4:]) - 1)
+ # print(objs,faces)
##if len(objs) == 1:
## if faces:
## Draft.makeShape2DView(objs[0],vec,facenumbers=faces)
## #return
new_sks = []
for o in objs:
- Draft.makeShape2DView(o,vec)
+ Draft.makeShape2DView(o, vec)
new_sks.append(FreeCAD.ActiveDocument.ActiveObject)
FreeCAD.ActiveDocument.recompute()
for s in new_sks:
- FreeCADGui.ActiveDocument.getObject(s.Name).LineColor = (85,170,255) #(1.00,1.00,1.00)
- FreeCADGui.ActiveDocument.getObject(s.Name).PointColor = (85,170,255) #(1.00,1.00,1.00)
+ FreeCADGui.ActiveDocument.getObject(s.Name).LineColor = (85, 170, 255) # (1.00,1.00,1.00)
+ FreeCADGui.ActiveDocument.getObject(s.Name).PointColor = (85, 170, 255) # (1.00,1.00,1.00)
else:
- reply = QtGui.QMessageBox.information(None,"Warning", "select something\nto project it to a 2D shape in the document")
- FreeCAD.Console.PrintError('select something\nto project it to a 2D shape in the document\n')
+ QtGui.QMessageBox.information(
+ None,
+ "Warning",
+ "select something\nto project it to a 2D shape in the document",
+ )
+ FreeCAD.Console.PrintError("select something\nto project it to a 2D shape in the document\n")
else:
- reply = QtGui.QMessageBox.information(None,"Warning", "select something\nto project it to a 2D shape in the document")
- FreeCAD.Console.PrintError('select something\nto project it to a 2D shape in the document\n')
-#
+ QtGui.QMessageBox.information(
+ None,
+ "Warning",
+ "select something\nto project it to a 2D shape in the document",
+ )
+ FreeCAD.Console.PrintError("select something\nto project it to a 2D shape in the document\n")
+
+
+FreeCADGui.addCommand("ksuTools3D2D", ksuTools3D2D())
+
-FreeCADGui.addCommand('ksuTools3D2D',ksuTools3D2D())
##
class ksuToolsTurnTable:
"ksu tools TurnTable"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'texture_turntable.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsTurnTable","TurnTable"),
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsTurnTable","ksu TurnTable")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "texture_turntable.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsTurnTable", "TurnTable"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsTurnTable", "ksu TurnTable"),
+ }
+
def IsActive(self):
- if FreeCAD.ActiveDocument is None:
- return False
- else:
- return True
-
+ return FreeCAD.ActiveDocument is not None
+
def Activated(self):
# do something here...
# https://forum.freecadweb.org/viewtopic.php?f=3&t=28795
-
+
## references
# My 2 favorite docs about coin are :
# http://www-evasion.imag.fr/~Francois.Fa ... index.html
# https://grey.colorado.edu/coin3d/annotated.html
-
- imgfilename = os.path.join( ksuWB_icons_path , '../textures/infinite_reflection_blur.png')
+
+ imgfilename = os.path.join(ksuWB_icons_path, "../textures/infinite_reflection_blur.png")
paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View")
- #old_AutoRotation = paramGet.GetBool("UseAutoRotation")
- #print(old_AutoRotation);print(paramGet.GetBool("UseAutoRotation"))
- paramGet.SetBool("UseAutoRotation",1)
+ # old_AutoRotation = paramGet.GetBool("UseAutoRotation")
+ # print(old_AutoRotation);print(paramGet.GetBool("UseAutoRotation"))
+ paramGet.SetBool("UseAutoRotation", 1)
sg = FreeCADGui.ActiveDocument.ActiveView.getSceneGraph()
tex = sg.getByName("myTexture")
tc = sg.getByName("myTextCoord")
- if tex: # remove existing
+ if tex: # remove existing
sg.removeChild(tex)
- else: # or insert a new one
- tex = coin.SoTexture2()
+ else: # or insert a new one
+ tex = coin.SoTexture2()
tex.setName("myTexture")
- #jpgfilename = QtGui.QFileDialog.getOpenFileName(QtGui.qApp.activeWindow(),'Open image file','*.jpg')
- #tex.filename = str(jpgfilename[0])
- #print(str(jpgfilename[0]))
+ # jpgfilename = QtGui.QFileDialog.getOpenFileName(QtGui.qApp.activeWindow(),'Open image file','*.jpg')
+ # tex.filename = str(jpgfilename[0])
+ # print(str(jpgfilename[0]))
tex.filename = str(imgfilename)
- #print (str(imgfilename))
- sg.insertChild(tex,1)
- FreeCADGui.ActiveDocument.ActiveView.startAnimating(0,1,0,0.2)
+ # print (str(imgfilename))
+ sg.insertChild(tex, 1)
+ FreeCADGui.ActiveDocument.ActiveView.startAnimating(0, 1, 0, 0.2)
if tc:
sg.removeChild(tc)
FreeCADGui.ActiveDocument.ActiveView.stopAnimating()
# uar = 0 if (old_AutoRotation) else 1
- #if (old_AutoRotation):
- # uar = 1
- #else:
+ # if (old_AutoRotation):
+ # uar = 1
+ # else:
# uar = 0
- #paramGet.SetBool("UseAutoRotation",uar)
- #print(old_AutoRotation);print (uar);print(paramGet.GetBool("UseAutoRotation"))
+ # paramGet.SetBool("UseAutoRotation",uar)
+ # print(old_AutoRotation);print (uar);print(paramGet.GetBool("UseAutoRotation"))
else:
tc = coin.SoTextureCoordinateEnvironment()
tc.setName("myTextCoord")
- sg.insertChild(tc,2)
-
+ sg.insertChild(tc, 2)
+
-FreeCADGui.addCommand('ksuToolsTurnTable',ksuToolsTurnTable())
+FreeCADGui.addCommand("ksuToolsTurnTable", ksuToolsTurnTable())
##
+
class ksuToolsConstrainator:
"ksu tools Constraint Sketch"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Sketcher_LockAll.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsConstrainator","Constrain a Sketch") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsConstrainator","ksu Fix & auto Constrain a Sketch")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Sketcher_LockAll.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsConstrainator", "Constrain a Sketch"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsConstrainator", "ksu Fix & auto Constrain a Sketch"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
sel = FreeCADGui.Selection.getSelection()
- if len(sel)==1:
- if sel[0].TypeId == 'Sketcher::SketchObject' and len(sel)==1:
+ if len(sel) == 1:
+ if sel[0].TypeId == "Sketcher::SketchObject" and len(sel) == 1:
CDialog = QtGui.QDialog()
ui = Ui_CDialog()
ui.setupUi(CDialog)
CDialog.setWindowTitle("Sketch Constrainator")
- reply=CDialog.exec_()
- if reply==1:
- FreeCAD.ActiveDocument.openTransaction('Constrainator')
- dialog_values = (ui.return_strings()) # window is value from edit field
- #print (dialog_values)
- for i,dv in enumerate (dialog_values): #py3 compatibility
+ reply = CDialog.exec_()
+ if reply == 1:
+ FreeCAD.ActiveDocument.openTransaction("Constrainator")
+ dialog_values = ui.return_strings() # window is value from edit field
+ # print (dialog_values)
+ for i, dv in enumerate(dialog_values): # py3 compatibility
if i == 0:
tol = float(dv)
if tol <= 0:
tol = 0.01
if i == 1:
- if 'True' in dv:
- constr = 'all'
- else:
- constr = 'coincident'
- if i ==2:
- if 'True' in dv:
- rmvXG = True
- else:
- rmvXG = False
+ constr = "all" if "True" in dv else "coincident"
+ if i == 2:
+ rmvXG = "True" in dv
if rmvXG:
sanitizeSkBsp(sel[0].Name, tol)
add_constraints(sel[0].Name, tol, constr)
skt = FreeCAD.ActiveDocument.getObject(sel[0].Name)
- if hasattr(skt, 'OpenVertices'):
+ if hasattr(skt, "OpenVertices"):
openVtxs = skt.OpenVertices
add_points = True
- if len(openVtxs) >0:
+ if len(openVtxs) > 0:
FreeCAD.Console.PrintError("Open Vertexes found.\n")
- FreeCAD.Console.PrintWarning(str(openVtxs)+'\n')
- msg = """Open Vertexes found.
"""+str(openVtxs)
- reply = QtGui.QMessageBox.information(None,"info", msg)
+ FreeCAD.Console.PrintWarning(str(openVtxs) + "\n")
+ msg = """Open Vertexes found.
""" + str(openVtxs)
+ reply = QtGui.QMessageBox.information(None, "info", msg)
if add_points:
for v in openVtxs:
- FreeCAD.ActiveDocument.addObject('PartDesign::Point','DatumPoint')
+ FreeCAD.ActiveDocument.addObject("PartDesign::Point", "DatumPoint")
dp = FreeCAD.ActiveDocument.ActiveObject
- dp.Placement = FreeCAD.Placement (FreeCAD.Vector(v[0],v[1],0), FreeCAD.Rotation(0,0,0), FreeCAD.Vector(0,0,0))
- dp.Label = 'OpenVertexPointer'
+ dp.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(v[0], v[1], 0),
+ FreeCAD.Rotation(0, 0, 0),
+ FreeCAD.Vector(0, 0, 0),
+ )
+ dp.Label = "OpenVertexPointer"
FreeCAD.ActiveDocument.commitTransaction()
else:
- reply = QtGui.QMessageBox.information(None,"Warning", "select a Sketch to be Fix & Constrained")
- FreeCAD.Console.PrintError('select a Sketch to be Fix & Constrained\n')
+ reply = QtGui.QMessageBox.information(None, "Warning", "select a Sketch to be Fix & Constrained")
+ FreeCAD.Console.PrintError("select a Sketch to be Fix & Constrained\n")
else:
- reply = QtGui.QMessageBox.information(None,"Warning", "select ONE Sketch to be Fix & Constrained")
- FreeCAD.Console.PrintError('select ONE Sketch to be Fix & Constrained\n')
-
+ reply = QtGui.QMessageBox.information(None, "Warning", "select ONE Sketch to be Fix & Constrained")
+ FreeCAD.Console.PrintError("select ONE Sketch to be Fix & Constrained\n")
+
+
+FreeCADGui.addCommand("ksuToolsConstrainator", ksuToolsConstrainator())
+
-FreeCADGui.addCommand('ksuToolsConstrainator',ksuToolsConstrainator())
##
class ksuToolsDiscretize:
"ksu tools Discretize"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Discretize.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsDiscretize","Discretize") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsDiscretize","ksu Discretize a shape/outline to a Sketch")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Discretize.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsDiscretize", "Discretize"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsDiscretize", "ksu Discretize a shape/outline to a Sketch"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
sel = FreeCADGui.Selection.getSelection()
if len(sel) != 1:
- reply = QtGui.QMessageBox.information(None,"Warning", "select one single object to be discretized")
- FreeCAD.Console.PrintError('select one single object to be discretized\n')
+ QtGui.QMessageBox.information(None, "Warning", "select one single object to be discretized")
+ FreeCAD.Console.PrintError("select one single object to be discretized\n")
else:
shapes = []
for selobj in sel:
for e in selobj.Shape.Edges:
# if not hasattr(e.Curve,'Radius'):
- if not e.Closed: # Arc and not Circle
- shapes.append(Part.makePolygon(e.discretize(QuasiDeflection=q_deflection)))
- elif e.Curve.TypeId == 'Part::GeomEllipse':
+ if not e.Closed or e.Curve.TypeId == "Part::GeomEllipse": # Arc and not Circle
shapes.append(Part.makePolygon(e.discretize(QuasiDeflection=q_deflection)))
else:
shapes.append(Part.Wire(e))
- #sd=e.copy().discretize(QuasiDeflection=dqd)
+ # sd=e.copy().discretize(QuasiDeflection=dqd)
Draft.makeSketch(shapes)
sk_d = FreeCAD.ActiveDocument.ActiveObject
if sk_d is not None:
- FreeCADGui.ActiveDocument.getObject(sk_d.Name).LineColor = (1.00,1.00,1.00)
- FreeCADGui.ActiveDocument.getObject(sk_d.Name).PointColor = (1.00,1.00,1.00)
- max_geo_admitted = 1500 # after this number, no recompute is applied
- if len (sk_d.Geometry) < max_geo_admitted:
+ FreeCADGui.ActiveDocument.getObject(sk_d.Name).LineColor = (1.00, 1.00, 1.00)
+ FreeCADGui.ActiveDocument.getObject(sk_d.Name).PointColor = (1.00, 1.00, 1.00)
+ max_geo_admitted = 1500 # after this number, no recompute is applied
+ if len(sk_d.Geometry) < max_geo_admitted:
FreeCAD.ActiveDocument.recompute()
-FreeCADGui.addCommand('ksuToolsDiscretize',ksuToolsDiscretize())
+
+FreeCADGui.addCommand("ksuToolsDiscretize", ksuToolsDiscretize())
+
+
##
##
class ksuToolsEdges2Sketch:
"ksu tools edge to sketch"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Edges2Sketch.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsEdges2Sketch","Edges to Sketch") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsEdges2Sketch","ksu Select coplanar edge(s) or Face(s) or \na single Vertex of a coplanar outline \nto get a corresponding Sketch")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Edges2Sketch.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsEdges2Sketch", "Edges to Sketch"),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "ksuToolsEdges2Sketch",
+ "ksu Select coplanar edge(s) or Face(s) or \na single Vertex of a coplanar outline \nto get a corresponding Sketch",
+ ),
+ }
+
def IsActive(self):
sel = FreeCADGui.Selection.getSelection()
- if len(sel) == 0:
- return False
- else:
- return True
-
+ return len(sel) != 0
+
def Activated(self):
# do something here...
ksu_edges2sketch()
-
-FreeCADGui.addCommand('ksuToolsEdges2Sketch',ksuToolsEdges2Sketch())
+
+
+FreeCADGui.addCommand("ksuToolsEdges2Sketch", ksuToolsEdges2Sketch())
##
+
class ksuToolsResetPartPlacement:
"ksu tools Reset PartPlacement"
+
#####################################
# Copyright (c) openBrain 2019
# Licensed under LGPL v2
@@ -2200,263 +2414,314 @@ class ksuToolsResetPartPlacement:
#
#####################################
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'resetPartPlacement.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsResetPartPlacement","Reset Part Placement") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsResetPartPlacement","ksu Reset Placement for all Part containers in selection")}
- def getLinkGlobalPlacement(self,ob):
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "resetPartPlacement.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsResetPartPlacement", "Reset Part Placement"),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "ksuToolsResetPartPlacement",
+ "ksu Reset Placement for all Part containers in selection",
+ ),
+ }
+
+ def getLinkGlobalPlacement(self, ob):
# print(ob.Name,'Link object')
# FreeCAD.Console.PrintMessage(ob.Parents)
# FreeCAD.Console.PrintWarning(ob.Parents[0][0].Name+' '+ob.Parents[0][1])
# FreeCAD.Console.PrintWarning(Part.getShape(ob.Parents[0][0],ob.Parents[0][1]).Placement)
# return ob.Label
- return Part.getShape(ob.Parents[0][0],ob.Parents[0][1]).Placement
- #
- def Activated(self):
+ return Part.getShape(ob.Parents[0][0], ob.Parents[0][1]).Placement
+
+ def Activated(self):
doc = FreeCAD.ActiveDocument
found_kSU_PCB = False
if doc is None:
FreeCAD.Console.Print("No Active Document found")
return
+ currState = {} # initialize a dictionary to store current object placements
+ sel = FreeCADGui.Selection.getSelection()
+ if sel[0].Placement != FreeCAD.Placement(FreeCAD.Vector(0, 0, 0), FreeCAD.Rotation(0, 0, 0)):
+ doc.openTransaction("Absolufy-kSU") # open a transaction for undo management
+ if sel[0].TypeId == "App::Part":
+ # https://forum.freecad.org/viewtopic.php?p=461588#p461588
+ # print('before',sel[0].Placement)
+ center = sel[0].Shape.BoundBox.Center
+ # using a temporary shape for moving placement
+ point = FreeCAD.ActiveDocument.addObject("Part::Vertex", "refPoint")
+ point.Placement = sel[0].Placement
+ point.Placement.move(-center)
+ # cent_Placement=sel[0].Placement
+ # cent_Placement.move(-center)
+ # print('after',sel[0].Placement)
+ for obj in sel[0].OutList: ## App.ActiveDocument.Objects: #going through active document objects
+ if obj.TypeId == "App::Part" and (
+ "Board_Geoms_" in obj.Label
+ or "Step_Models_" in obj.Label
+ or "Step_Virtual_Models_" in obj.Label
+ ):
+ # print (obj.Label)
+ comp_plc = obj.Placement.multiply(point.Placement) # .inverse()) #sel[0].Placement.inverse()
+ ## comp_plc = obj.Placement.multiply(cent_Placement) #.inverse()) #sel[0].Placement.inverse()
+ # comp_plc = obj.Placement.multiply(sel[0].Placement) #.inverse()) #sel[0].Placement.inverse()
+ obj.Placement = comp_plc
+ # sel[0].Placement.move(center)
+ obj.Placement.move(center)
+ found_kSU_PCB = True
+ if found_kSU_PCB:
+ print("applyied reset Part Placement on kSU pcb sub Parts")
+ sel[0].Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, 0, 0),
+ FreeCAD.Rotation(0, 0, 0),
+ ) # reset its placement to global document origin
+ FreeCAD.ActiveDocument.removeObject(point.Name)
+ if not found_kSU_PCB:
+ for obj in sel: ## App.ActiveDocument.Objects: #going through active document objects
+ if (
+ "Placement" in obj.PropertiesList
+ and obj.TypeId != "Sketcher::SketchObject"
+ and "body object" not in str(obj.InList)
+ ): # if object has a Placement property
+ # FreeCAD.Console.PrintWarning(obj.TypeId)
+ if hasattr(obj, "getGlobalPlacement"):
+ currState[obj] = (
+ obj.getGlobalPlacement()
+ ) # store the object pointer with its global placement
+ # elif obj.TypeId == 'App::Link':
+ # obj.getLinkGlobalPlacement()
+ for o in obj.OutListRecursive:
+ if (
+ "Placement" in o.PropertiesList
+ and o.TypeId != "Sketcher::SketchObject"
+ and "body object" not in str(o.InList)
+ ): # if object has a Placement property
+ # FreeCAD.Console.PrintWarning(o.TypeId)
+ if hasattr(o, "getGlobalPlacement"):
+ currState[o] = (
+ o.getGlobalPlacement()
+ ) # store the object pointer with its global placement
+ elif o.TypeId == "App::Link":
+ plc = Part.getShape(
+ o.Parents[0][0],
+ o.Parents[0][1],
+ ).Placement # getLinkGlobalPlacement(o)
+ # print(o.Label+' App::Link')
+ # print(plc)
+ # pp.inverse().multiply(plp)
+ if len(o.OutList) == 1:
+ if "Part object" in str(o.OutList[0]): # Link Part container
+ # print(o.Parents[0][0].Label+' Part-base calc plac',o.Parents[0][0].Placement)
+ # print(o.OutList[0].Label+' Part-base calc plac',o.OutList[0].Placement)
+ # print(o.Label+' Part-App::Link plac',o.Placement)
+ # comp_plc = o.Placement.multiply(o.Parents[0][0].Placement.inverse()) # plc.inverse().multiply(o.Placement) #o.Parents[0][0].Placement.inverse().multiply(o.Placement)
+ comp_plc = o.Placement.multiply(o.OutList[0].Placement.inverse())
+ # print(o.Label+' Part-App::Link calc plac',comp_plc)
+ currState[o] = comp_plc
+ else:
+ currState[o] = plc
+ # FreeCAD.ActiveDocument.openTransaction("Absolufy") #open a transaction for undo management
+ for obj, plac in currState.items(): # going through all moveable objects
+ if obj.isDerivedFrom("App::Part"): # if object is a part container
+ obj.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, 0, 0),
+ FreeCAD.Rotation(0, 0, 0),
+ ) # reset its placement to global document origin
+ # or obj.isDerivedFrom("App::Link")
+ # elif len(obj.OutList) == 1:
+ # if 'Part object' in str(obj.OutList[0]): #Link Part container
+ # print(obj.Label+' Part-App::Link new plac',plac)
+ # obj.Placement = plac
+ # # obj.Placement = mainP_origP.inverse().multiply(plac)
+ # else: #for all other objects Link obj
+ # obj.Placement = plac
+ elif (
+ obj.TypeId[:5] == "App::" and obj.TypeId != "App::Link"
+ ): # if object is another App type (typically an origin axis or plane)
+ None # do nothing
+ else: # for all other objects Link obj
+ obj.Placement = plac
+ # elif not(obj.isDerivedFrom("App::Link")):
+ # obj.Placement = plac
+ # else:
+ # obj.Placement = sel[0].Placement.multiply(plac) #replace them at their global (absolute) placement
+ # if hasattr(obj, 'LinkedObject'):
+ # print(obj.LinkedObject)
+ # if 'Part::PartFeature' not in str(obj.LinkedObject):
+ # # if obj.LinkedObject == 'Part::PartFeature':
+ # print(obj.LinkedObject,'here')
+ # obj.Placement = plac #replace them at their global (absolute) placement
+ # else:
+ # None
+ print("applyied reset Part Placement base")
+ doc.commitTransaction() # commit transaction
+ doc.recompute()
else:
- currState = {} #initialize a dictionary to store current object placements
- sel = FreeCADGui.Selection.getSelection()
- if sel[0].Placement != FreeCAD.Placement(FreeCAD.Vector(0,0,0),FreeCAD.Rotation(0,0,0)):
- doc.openTransaction("Absolufy-kSU") #open a transaction for undo management
- if sel[0].TypeId == 'App::Part':
- # https://forum.freecad.org/viewtopic.php?p=461588#p461588
- # print('before',sel[0].Placement)
- center = sel[0].Shape.BoundBox.Center
- # using a temporary shape for moving placement
- point = FreeCAD.ActiveDocument.addObject("Part::Vertex", "refPoint")
- point.Placement = sel[0].Placement
- point.Placement.move(-center)
- # cent_Placement=sel[0].Placement
- # cent_Placement.move(-center)
- # print('after',sel[0].Placement)
- for obj in sel[0].OutList: ## App.ActiveDocument.Objects: #going through active document objects
- if obj.TypeId == 'App::Part' and ('Board_Geoms_' in obj.Label or 'Step_Models_' in obj.Label or 'Step_Virtual_Models_' in obj.Label):
- # print (obj.Label)
- comp_plc = obj.Placement.multiply(point.Placement) #.inverse()) #sel[0].Placement.inverse()
- ## comp_plc = obj.Placement.multiply(cent_Placement) #.inverse()) #sel[0].Placement.inverse()
- # comp_plc = obj.Placement.multiply(sel[0].Placement) #.inverse()) #sel[0].Placement.inverse()
- obj.Placement=comp_plc
- #sel[0].Placement.move(center)
- obj.Placement.move(center)
- found_kSU_PCB = True
- if found_kSU_PCB:
- print('applyied reset Part Placement on kSU pcb sub Parts')
- sel[0].Placement = FreeCAD.Placement(FreeCAD.Vector(0,0,0),FreeCAD.Rotation(0,0,0)) #reset its placement to global document origin
- FreeCAD.ActiveDocument.removeObject(point.Name)
- if not found_kSU_PCB:
- for obj in sel: ## App.ActiveDocument.Objects: #going through active document objects
- if "Placement" in obj.PropertiesList and obj.TypeId != 'Sketcher::SketchObject' \
- and 'body object' not in str(obj.InList): #if object has a Placement property
- #FreeCAD.Console.PrintWarning(obj.TypeId)
- if hasattr(obj,'getGlobalPlacement'):
- currState[obj] = obj.getGlobalPlacement() #store the object pointer with its global placement
- #elif obj.TypeId == 'App::Link':
- # obj.getLinkGlobalPlacement()
- for o in obj.OutListRecursive:
- if "Placement" in o.PropertiesList and o.TypeId != 'Sketcher::SketchObject' \
- and 'body object' not in str(o.InList): #if object has a Placement property
- #FreeCAD.Console.PrintWarning(o.TypeId)
- if hasattr(o,'getGlobalPlacement'):
- currState[o] = o.getGlobalPlacement() #store the object pointer with its global placement
- elif o.TypeId == 'App::Link':
- plc = Part.getShape(o.Parents[0][0],o.Parents[0][1]).Placement #getLinkGlobalPlacement(o)
- # print(o.Label+' App::Link')
- # print(plc)
- #pp.inverse().multiply(plp)
- if len(o.OutList) == 1:
- if 'Part object' in str(o.OutList[0]): #Link Part container
- #print(o.Parents[0][0].Label+' Part-base calc plac',o.Parents[0][0].Placement)
- # print(o.OutList[0].Label+' Part-base calc plac',o.OutList[0].Placement)
- # print(o.Label+' Part-App::Link plac',o.Placement)
- #comp_plc = o.Placement.multiply(o.Parents[0][0].Placement.inverse()) # plc.inverse().multiply(o.Placement) #o.Parents[0][0].Placement.inverse().multiply(o.Placement)
- comp_plc = o.Placement.multiply(o.OutList[0].Placement.inverse())
- # print(o.Label+' Part-App::Link calc plac',comp_plc)
- currState[o] = comp_plc
- else:
- currState[o] = plc
- # FreeCAD.ActiveDocument.openTransaction("Absolufy") #open a transaction for undo management
- for obj, plac in currState.items(): #going through all moveable objects
- if obj.isDerivedFrom("App::Part"): #if object is a part container
- obj.Placement = FreeCAD.Placement(FreeCAD.Vector(0,0,0),FreeCAD.Rotation(0,0,0)) #reset its placement to global document origin
- # or obj.isDerivedFrom("App::Link")
- #elif len(obj.OutList) == 1:
- # if 'Part object' in str(obj.OutList[0]): #Link Part container
- # print(obj.Label+' Part-App::Link new plac',plac)
- # obj.Placement = plac
- # # obj.Placement = mainP_origP.inverse().multiply(plac)
- # else: #for all other objects Link obj
- # obj.Placement = plac
- elif obj.TypeId[:5] == "App::" and obj.TypeId != 'App::Link': #if object is another App type (typically an origin axis or plane)
- None #do nothing
- else: #for all other objects Link obj
- obj.Placement = plac
- # elif not(obj.isDerivedFrom("App::Link")):
- # obj.Placement = plac
- # else:
- # obj.Placement = sel[0].Placement.multiply(plac) #replace them at their global (absolute) placement
- # if hasattr(obj, 'LinkedObject'):
- # print(obj.LinkedObject)
- # if 'Part::PartFeature' not in str(obj.LinkedObject):
- # # if obj.LinkedObject == 'Part::PartFeature':
- # print(obj.LinkedObject,'here')
- # obj.Placement = plac #replace them at their global (absolute) placement
- # else:
- # None
- print('applyied reset Part Placement base')
- doc.commitTransaction() #commit transaction
- doc.recompute()
- else:
- FreeCAD.Console.PrintMessage("Placement already Zero\n")
+ FreeCAD.Console.PrintMessage("Placement already Zero\n")
return
def IsActive(self):
- import FreeCAD, FreeCADGui, Part
+ import FreeCAD
+ import FreeCADGui
+
doc = FreeCAD.activeDocument()
if doc is None:
return False
- else:
- sel = FreeCADGui.Selection.getSelection()
- if len(sel) >1 or len(sel)==0:
- return False
- elif len(sel)==1:
- if hasattr(sel[0], 'TypeId'):
- if (sel[0].TypeId) != 'App::Part':
- return False
- return True
-FreeCADGui.addCommand('ksuToolsResetPartPlacement',ksuToolsResetPartPlacement())
+ sel = FreeCADGui.Selection.getSelection()
+ if len(sel) > 1 or len(sel) == 0:
+ return False
+ return not (len(sel) == 1 and hasattr(sel[0], "TypeId") and sel[0].TypeId != "App::Part")
+
+
+FreeCADGui.addCommand("ksuToolsResetPartPlacement", ksuToolsResetPartPlacement())
##
+
class ksuToolsResetPlacement:
"ksu tools Reset Placement"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'resetPlacement.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsResetPlacement","Reset Placement") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsResetPlacement","ksu Reset Placement for a Shape")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "resetPlacement.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsResetPlacement", "Reset Placement"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsResetPlacement", "ksu Reset Placement for a Shape"),
+ }
+
def IsActive(self):
doc = FreeCAD.activeDocument()
- if doc is None: return False
- sel = FreeCADGui.Selection.getSelection()
- if len(sel) >1 or len(sel)==0:
- return False
- elif sel[0].TypeId == 'App::Part':
+ if doc is None:
return False
- return True
-
+ sel = FreeCADGui.Selection.getSelection()
+ return not (len(sel) > 1 or len(sel) == 0 or sel[0].TypeId == "App::Part")
+
def Activated(self):
# do something here...
sel = FreeCADGui.Selection.getSelection()
if len(sel) != 1:
- reply = QtGui.QMessageBox.information(None,"Warning", "select one single object to Reset its Placement")
- FreeCAD.Console.PrintError('select one single object to Reset its Placement\n')
+ QtGui.QMessageBox.information(None, "Warning", "select one single object to Reset its Placement")
+ FreeCAD.Console.PrintError("select one single object to Reset its Placement\n")
+ elif sel[0].Placement != FreeCAD.Placement(FreeCAD.Vector(0, 0, 0), FreeCAD.Rotation(0, 0, 0)):
+ FreeCAD.ActiveDocument.openTransaction("Absolufy") # open a transaction for undo management
+ import kicadStepUptools
+
+ FreeCAD.ActiveDocument.openTransaction("rst")
+ kicadStepUptools.routineResetPlacement(keepWB=True)
+ FreeCAD.ActiveDocument.commitTransaction()
else:
- if sel[0].Placement != FreeCAD.Placement(FreeCAD.Vector(0,0,0),FreeCAD.Rotation(0,0,0)):
- FreeCAD.ActiveDocument.openTransaction("Absolufy") #open a transaction for undo management
- import kicadStepUptools
- FreeCAD.ActiveDocument.openTransaction('rst')
- kicadStepUptools.routineResetPlacement(keepWB=True)
- FreeCAD.ActiveDocument.commitTransaction()
- else:
- FreeCAD.Console.PrintMessage("Placement already Zero\n")
-FreeCADGui.addCommand('ksuToolsResetPlacement',ksuToolsResetPlacement())
+ FreeCAD.Console.PrintMessage("Placement already Zero\n")
+
+
+FreeCADGui.addCommand("ksuToolsResetPlacement", ksuToolsResetPlacement())
##
+
#####
class ksuTools2D2Sketch:
"ksu tools 2D to Sketch object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , '2DtoSketch.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuTools2D2Sketch","2D to Sketch") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuTools2D2Sketch","ksu 2D object (or DXF) to Sketch")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "2DtoSketch.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuTools2D2Sketch", "2D to Sketch"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuTools2D2Sketch", "ksu 2D object (or DXF) to Sketch"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
- max_geo_admitted = 1500 # after this number, no recompute is applied
+ max_geo_admitted = 1500 # after this number, no recompute is applied
try:
- #for edge in edges:
+ # for edge in edges:
# print "geomType ",DraftGeomUtils.geomType(edge)
##face = OpenSCAD2Dgeom.edgestofaces(edges)
import kicadStepUptools
+
if reload_Gui:
- reload_lib( kicadStepUptools )
- #face = OpenSCAD2DgeomMau.edgestofaces(edges)
- FC_majorV=int(float(FreeCAD.Version()[0]))
- FC_minorV=int(float(FreeCAD.Version()[1]))
- using_draft_makeSketch=True
- exposingInternalGeo=False
- faceobj=None
- if not using_draft_makeSketch or (FC_majorV==0 and FC_minorV<=16):
- edges=sum((obj.Shape.Edges for obj in \
- FreeCADGui.Selection.getSelection() if hasattr(obj,'Shape')),[])
+ reload_lib(kicadStepUptools)
+ # face = OpenSCAD2DgeomMau.edgestofaces(edges)
+ FC_majorV = int(float(FreeCAD.Version()[0]))
+ FC_minorV = int(float(FreeCAD.Version()[1]))
+ using_draft_makeSketch = True
+ exposingInternalGeo = False
+ faceobj = None
+ if not using_draft_makeSketch or (FC_majorV == 0 and FC_minorV <= 16):
+ edges = functools.reduce(
+ operator.iadd,
+ (obj.Shape.Edges for obj in FreeCADGui.Selection.getSelection() if hasattr(obj, "Shape")),
+ [],
+ )
try:
- faceobj=None
- face = kicadStepUptools.OSCD2Dg_edgestofaces(edges,3 , kicadStepUptools.edge_tolerance)
- face.check() # reports errors
- face.fix(0,0,0)
- faceobj = FreeCAD.ActiveDocument.addObject('Part::Feature',"Face")
+ faceobj = None
+ face = kicadStepUptools.OSCD2Dg_edgestofaces(edges, 3, kicadStepUptools.edge_tolerance)
+ face.check() # reports errors
+ face.fix(0, 0, 0)
+ faceobj = FreeCAD.ActiveDocument.addObject("Part::Feature", "Face")
faceobj.Label = "Face"
faceobj.Shape = face
for obj in FreeCADGui.Selection.getSelection():
- FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility=False
+ FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility = False
FreeCAD.ActiveDocument.recompute()
- wires,_faces = Draft.downgrade(faceobj,delete=True)
+ wires, _faces = Draft.downgrade(faceobj, delete=True)
except:
import Draft
+
if faceobj is not None:
FreeCAD.ActiveDocument.removeObject(faceobj.Name)
sk = None
- sk = Draft.makeSketch(FreeCADGui.Selection.getSelection(),autoconstraints=True)
+ sk = Draft.makeSketch(FreeCADGui.Selection.getSelection(), autoconstraints=True)
if sk is None:
- reply = QtGui.QMessageBox.information(None,"Warning", "Select edge elements to be converted to Sketch\nBSplines and Bezier curves are not supported by this tool")
- FreeCAD.Console.PrintWarning("Select edge elements to be converted to Sketch\nBSplines and Bezier curves are not supported by this tool\n")
+ QtGui.QMessageBox.information(
+ None,
+ "Warning",
+ "Select edge elements to be converted to Sketch\nBSplines and Bezier curves are not supported by this tool",
+ )
+ FreeCAD.Console.PrintWarning(
+ "Select edge elements to be converted to Sketch\nBSplines and Bezier curves are not supported by this tool\n",
+ )
stop
sk.Label = "Sketch_converted"
- sname=FreeCAD.ActiveDocument.ActiveObject.Name
- using_draft_makeSketch=True
+ sname = FreeCAD.ActiveDocument.ActiveObject.Name
+ using_draft_makeSketch = True
for obj in FreeCADGui.Selection.getSelection():
- FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility=False
-
- if FC_majorV==0 and FC_minorV>=16:
+ FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility = False
+
+ if FC_majorV == 0 and FC_minorV >= 16:
try:
sketch = Draft.makeSketch(wires[0:1])
sketch.Label = "Sketch_converted"
for wire in wires[1:]:
- Draft.makeSketch([wire],addTo=sketch)
- sname=FreeCAD.ActiveDocument.ActiveObject.Name
+ Draft.makeSketch([wire], addTo=sketch)
+ sname = FreeCAD.ActiveDocument.ActiveObject.Name
except:
- sname=FreeCAD.ActiveDocument.ActiveObject.Name
+ sname = FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.removeObject(sname)
- reply = QtGui.QMessageBox.information(None,"Error", "BSplines not supported in FC0.16\nUse FC0.17")
- #sname=FreeCAD.ActiveDocument.ActiveObject.Name
+ QtGui.QMessageBox.information(None, "Error", "BSplines not supported in FC0.16\nUse FC0.17")
+ # sname=FreeCAD.ActiveDocument.ActiveObject.Name
for wire in wires:
FreeCAD.ActiveDocument.removeObject(wire.Name)
- #FreeCAD.Console.PrintWarning("\nConverting Bezier curves to Arcs\n")
- #wires,_faces = Draft.downgrade(faceobj,delete=True)
- ##elif using_draft_makeSketch == False:
+ # FreeCAD.Console.PrintWarning("\nConverting Bezier curves to Arcs\n")
+ # wires,_faces = Draft.downgrade(faceobj,delete=True)
+ ##elif using_draft_makeSketch == False:
newShapeList = []
newShapes = []
- found_BCurve=False
newBSlEdges = []
- #stop
+ # stop
for wire in wires:
for e in wire.Shape.Edges:
if DraftGeomUtils.geomType(e) == "BSplineCurve":
- #print 'found BSpline'
- found_BCurve=True
+ # print 'found BSpline'
newBSlEdges.append(e)
elif DraftGeomUtils.geomType(e) == "BezierCurve":
- #print 'found BezierCurve'
- found_BCurve=True
+ # print 'found BezierCurve'
edges = []
newspline = e.Curve.toBSpline()
arcs = newspline.toBiArcs(precision)
@@ -2464,62 +2729,62 @@ def Activated(self):
edges.append(Part.Edge(i))
w = Part.Wire([Part.Edge(i) for i in edges])
Part.show(w)
- w_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ w_name = FreeCAD.ActiveDocument.ActiveObject.Name
newShapeList.append(w_name)
- wn=FreeCAD.ActiveDocument.getObject(w_name)
+ wn = FreeCAD.ActiveDocument.getObject(w_name)
newShapes.append(wn)
else:
- #print 'found STD Geom'
+ # print 'found STD Geom'
w = Part.Wire(e)
Part.show(w)
newShapes.append(w)
w_name = FreeCAD.ActiveDocument.ActiveObject.Name
newShapeList.append(w_name)
-
- #stop
- #print newShapes
- if len(newShapes)>0: #at least a STD geometry exists
+
+ # stop
+ # print newShapes
+ if len(newShapes) > 0: # at least a STD geometry exists
sketch = Draft.makeSketch(newShapes[0])
- FreeCAD.ActiveDocument.ActiveObject.Label="Sketch_conv"
- sname=FreeCAD.ActiveDocument.ActiveObject.Name
-
- if len(newShapes)>1: #at least a STD geometry exists
+ FreeCAD.ActiveDocument.ActiveObject.Label = "Sketch_conv"
+ sname = FreeCAD.ActiveDocument.ActiveObject.Name
+
+ if len(newShapes) > 1: # at least a STD geometry exists
for w in newShapes[1:]:
- Draft.makeSketch([w],addTo=sketch)
+ Draft.makeSketch([w], addTo=sketch)
FreeCAD.ActiveDocument.recompute()
for e in newBSlEdges:
# sk = FreeCAD.ActiveDocument.addObject('Sketcher::SketchObject','Sketch_bsp')
# sk.addGeometry(e.Curve, False)
sketch.addGeometry(e.Curve, False)
# Sketcher magic function :
- for i in range(0, len(sketch.Geometry)):
- try:
- if 'BSpline' in str(sketch.Geometry[i]):
+ for i in range(len(sketch.Geometry)):
+ try:
+ if "BSpline" in str(sketch.Geometry[i]):
sketch.exposeInternalGeometry(i)
except:
- #print 'error'
+ # print 'error'
pass
FreeCAD.ActiveDocument.recompute()
- FreeCAD.ActiveDocument.getObject(sname).Label="Sketch_converted"
- #Draft.makeSketch([w])
- elif FC_majorV==0 and FC_minorV>=16:
- if len (newBSlEdges)>0:
- sketch = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Sketch_conv')
+ FreeCAD.ActiveDocument.getObject(sname).Label = "Sketch_converted"
+ # Draft.makeSketch([w])
+ elif FC_majorV == 0 and FC_minorV >= 16:
+ if len(newBSlEdges) > 0:
+ sketch = FreeCAD.activeDocument().addObject("Sketcher::SketchObject", "Sketch_conv")
sname = sketch.Name
- FreeCAD.ActiveDocument.getObject(sname).Label="Sketch_converted"
+ FreeCAD.ActiveDocument.getObject(sname).Label = "Sketch_converted"
for e in newBSlEdges:
# sk = FreeCAD.ActiveDocument.addObject('Sketcher::SketchObject','Sketch_bsp')
# sk.addGeometry(e.Curve, False)
sketch.addGeometry(e.Curve, False)
# Sketcher magic function :
- for i in range(0, len(sketch.Geometry)):
- try:
- if 'BSpline' in str(sketch.Geometry[i]):
+ for i in range(len(sketch.Geometry)):
+ try:
+ if "BSpline" in str(sketch.Geometry[i]):
sketch.exposeInternalGeometry(i)
except:
- #print 'error'
+ # print 'error'
pass
- FreeCAD.ActiveDocument.recompute()
+ FreeCAD.ActiveDocument.recompute()
for wire in wires:
FreeCAD.ActiveDocument.removeObject(wire.Name)
for wnm in newShapeList:
@@ -2527,267 +2792,322 @@ def Activated(self):
FreeCAD.ActiveDocument.recompute()
else:
import Draft
+
if faceobj is not None:
FreeCAD.ActiveDocument.removeObject(faceobj.Name)
sk = None
- sk = Draft.makeSketch(FreeCADGui.Selection.getSelection(),autoconstraints=True)
+ sk = Draft.makeSketch(FreeCADGui.Selection.getSelection(), autoconstraints=True)
if sk is None:
- reply = QtGui.QMessageBox.information(None,"Warning", "Select edge elements to be converted to Sketch")
+ QtGui.QMessageBox.information(None, "Warning", "Select edge elements to be converted to Sketch")
FreeCAD.Console.PrintWarning("Select edge elements to be converted to Sketch\n")
stop
sk.Label = "Sketch_converted"
- sname=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.ActiveObject.ViewObject.LineColor = (1.00,1.00,1.00)
- FreeCAD.ActiveDocument.ActiveObject.ViewObject.PointColor = (1.00,1.00,1.00)
- if exposingInternalGeo: #this is particularly intensive in calculation for BSplines
- for i,g in enumerate (sk.Geometry):
- if 'BSplineCurve object' in str(g):
+ sname = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.ActiveObject.ViewObject.LineColor = (1.00, 1.00, 1.00)
+ FreeCAD.ActiveDocument.ActiveObject.ViewObject.PointColor = (1.00, 1.00, 1.00)
+ if exposingInternalGeo: # this is particularly intensive in calculation for BSplines
+ for i, g in enumerate(sk.Geometry):
+ if "BSplineCurve object" in str(g):
sk.exposeInternalGeometry(i)
- using_draft_makeSketch=True
+ using_draft_makeSketch = True
for obj in FreeCADGui.Selection.getSelection():
- FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility=False
- if len (sk.Geometry) < max_geo_admitted:
+ FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility = False
+ if len(sk.Geometry) < max_geo_admitted:
FreeCAD.ActiveDocument.recompute()
- except Part.OCCError: # Exception: #
- FreeCAD.Console.PrintError('Error in source %s (%s)' % (faceobj.Name,faceobj.Label)+"\n")
+ except Part.OCCError: # Exception: #
+ FreeCAD.Console.PrintError(f"Error in source {faceobj.Name} ({faceobj.Label})" + "\n")
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select elements to be converted to Sketch")
- FreeCAD.Console.PrintWarning("Select elements to be converted to Sketch\n")
-
- pass
-#
-FreeCADGui.addCommand('ksuTools2D2Sketch',ksuTools2D2Sketch())
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select elements to be converted to Sketch")
+ FreeCAD.Console.PrintWarning("Select elements to be converted to Sketch\n")
+
+
+FreeCADGui.addCommand("ksuTools2D2Sketch", ksuTools2D2Sketch())
+
#####
class ksuTools2DtoFace:
"ksu tools 2D to Sketch object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , '2DtoFace.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuTools2DtoFace","2D to Face") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuTools2DtoFace","ksu 2D object (or DXF) to Surface for extruding")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "2DtoFace.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuTools2DtoFace", "2D to Face"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuTools2DtoFace", "ksu 2D object (or DXF) to Surface for extruding"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
try:
- edges=sum((obj.Shape.Edges for obj in \
- FreeCADGui.Selection.getSelection() if hasattr(obj,'Shape')),[])
- #for edge in edges:
+ edges = functools.reduce(
+ operator.iadd,
+ (obj.Shape.Edges for obj in FreeCADGui.Selection.getSelection() if hasattr(obj, "Shape")),
+ [],
+ )
+ # for edge in edges:
# print "geomType ",DraftGeomUtils.geomType(edge)
import kicadStepUptools
+
if reload_Gui:
- reload_lib( kicadStepUptools )
- face = kicadStepUptools.OSCD2Dg_edgestofaces(edges,3 , kicadStepUptools.edge_tolerance)
+ reload_lib(kicadStepUptools)
+ face = kicadStepUptools.OSCD2Dg_edgestofaces(edges, 3, kicadStepUptools.edge_tolerance)
##face = OpenSCAD2Dgeom.edgestofaces(edges)
- #face = OpenSCAD2DgeomMau.edgestofaces(edges)
- face.check() # reports errors
- face.fix(0,0,0)
- faceobj = FreeCAD.ActiveDocument.addObject('Part::Feature',"Face")
+ # face = OpenSCAD2DgeomMau.edgestofaces(edges)
+ face.check() # reports errors
+ face.fix(0, 0, 0)
+ faceobj = FreeCAD.ActiveDocument.addObject("Part::Feature", "Face")
faceobj.Label = "Face"
faceobj.Shape = face
for obj in FreeCADGui.Selection.getSelection():
- FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility=False
+ FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility = False
FreeCAD.ActiveDocument.recompute()
- pass
- except Part.OCCError: # Exception: #
- FreeCAD.Console.PrintError('Error in source %s (%s)' % (faceobj.Name,faceobj.Label)+"\n")
+ except Part.OCCError: # Exception: #
+ FreeCAD.Console.PrintError(f"Error in source {faceobj.Name} ({faceobj.Label})" + "\n")
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select elements to be converted to Face")
- FreeCAD.Console.PrintWarning("Select elements to be converted to Face\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select elements to be converted to Face")
+ FreeCAD.Console.PrintWarning("Select elements to be converted to Face\n")
+
-FreeCADGui.addCommand('ksuTools2DtoFace',ksuTools2DtoFace())
+FreeCADGui.addCommand("ksuTools2DtoFace", ksuTools2DtoFace())
#####
+
class ksuToolsSimplifySketck:
"ksu tools Simplify Sketch object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'SimplifySketch.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsSimplifySketck","Simplify Sketch") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsSimplifySketck","ksu Simplifying Sketch to Arcs and Lines")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "SimplifySketch.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsSimplifySketck", "Simplify Sketch"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsSimplifySketck", "ksu Simplifying Sketch to Arcs and Lines"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
if len(FreeCADGui.Selection.getSelection()):
import kicadStepUptools
+
if reload_Gui:
- reload_lib( kicadStepUptools )
+ reload_lib(kicadStepUptools)
FreeCAD.Gui.activeDocument().activeView().viewTop()
kicadStepUptools.simplify_sketch()
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select ONE Sketch to be Simplified")
- FreeCAD.Console.PrintWarning("Select ONE Sketch to be Simplified\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select ONE Sketch to be Simplified")
+ FreeCAD.Console.PrintWarning("Select ONE Sketch to be Simplified\n")
+
-FreeCADGui.addCommand('ksuToolsSimplifySketck',ksuToolsSimplifySketck())
+FreeCADGui.addCommand("ksuToolsSimplifySketck", ksuToolsSimplifySketck())
#####
+
class ksuToolsBsplineNormalize:
"ksu tools Normalize Bspline for KiCAD format"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Sketcher_BSplineNormalize.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsBsplineNormalize","Geo to Bspline") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsBsplineNormalize","ksu Convert Geometry to Bspline for KiCAD format")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Sketcher_BSplineNormalize.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsBsplineNormalize", "Geo to Bspline"),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "ksuToolsBsplineNormalize",
+ "ksu Convert Geometry to Bspline for KiCAD format",
+ ),
+ }
+
def IsActive(self):
return True
- #return False
-
+ # return False
+
def Activated(self):
# do something here...
if len(FreeCADGui.Selection.getSelection()):
import kicadStepUptools
+
if reload_Gui:
- reload_lib( kicadStepUptools )
+ reload_lib(kicadStepUptools)
kicadStepUptools.normalize_bsplines()
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select ONE Sketch to be Normalized")
- FreeCAD.Console.PrintWarning("Select ONE Sketch to be Normalized\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select ONE Sketch to be Normalized")
+ FreeCAD.Console.PrintWarning("Select ONE Sketch to be Normalized\n")
+
+
+FreeCADGui.addCommand("ksuToolsBsplineNormalize", ksuToolsBsplineNormalize())
-FreeCADGui.addCommand('ksuToolsBsplineNormalize',ksuToolsBsplineNormalize())
#####
class ksuToolsFootprintGen:
"ksu tools Footprint generator object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'exportFootprint.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsFootprintGen","Footprint generator") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsFootprintGen","ksu Footprint editor and exporter")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "exportFootprint.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsFootprintGen", "Footprint generator"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsFootprintGen", "ksu Footprint editor and exporter"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- #for edge in edges:
+ FreeCADGui.Selection.getSelection()
+ # for edge in edges:
# print "geomType ",DraftGeomUtils.geomType(edge)
import kicadStepUptools
+
if reload_Gui:
- reload_lib( kicadStepUptools )
+ reload_lib(kicadStepUptools)
kicadStepUptools.PushFootprint()
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select Group or Sketch/Text elements to be converted to KiCad Footprint")
- FreeCAD.Console.PrintWarning("Select Group or Sketch/Text elements to be converted to KiCad Footprint\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(
+ None,
+ "Warning",
+ "Select Group or Sketch/Text elements to be converted to KiCad Footprint",
+ )
+ FreeCAD.Console.PrintWarning("Select Group or Sketch/Text elements to be converted to KiCad Footprint\n")
-FreeCADGui.addCommand('ksuToolsFootprintGen',ksuToolsFootprintGen())
+
+FreeCADGui.addCommand("ksuToolsFootprintGen", ksuToolsFootprintGen())
#####
+
class ksuToolsStepImportModeSTD:
"ksu tools full STEP Import Mode"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'ImportModeSTD.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsStepImportModeSTD","disable Full STEP Import Mode") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsStepImportModeSTD","ksu tools disable Full STEP Import Mode")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "ImportModeSTD.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsStepImportModeSTD", "disable Full STEP Import Mode"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsStepImportModeSTD", "ksu tools disable Full STEP Import Mode"),
+ }
+
def IsActive(self):
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- ReadShapeCompoundMode_status=paramGetVS.GetBool("ReadShapeCompoundMode")
- if not ReadShapeCompoundMode_status:
- return True
- else:
- return False
+ ReadShapeCompoundMode_status = paramGetVS.GetBool("ReadShapeCompoundMode")
+ return bool(not ReadShapeCompoundMode_status)
def Activated(self):
# do something here...
##ReadShapeCompoundMode
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- ReadShapeCompoundMode_status=paramGetVS.GetBool("ReadShapeCompoundMode")
- #sayerr("checking ReadShapeCompoundMode")
- FreeCAD.Console.PrintWarning("ReadShapeCompoundMode status "+str(ReadShapeCompoundMode_status)+'\n')
- #if ReadShapeCompoundMode_status:
+ ReadShapeCompoundMode_status = paramGetVS.GetBool("ReadShapeCompoundMode")
+ # sayerr("checking ReadShapeCompoundMode")
+ FreeCAD.Console.PrintWarning("ReadShapeCompoundMode status " + str(ReadShapeCompoundMode_status) + "\n")
+ # if ReadShapeCompoundMode_status:
# paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
# paramGetVS.SetBool("ReadShapeCompoundMode",False)
# FreeCAD.Console.PrintWarning("disabling ReadShapeCompoundMode"+'\n')
if not ReadShapeCompoundMode_status:
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- paramGetVS.SetBool("ReadShapeCompoundMode",True)
- FreeCAD.Console.PrintError("enabling ReadShapeCompoundMode -> Simplified Mode"+'\n')
+ paramGetVS.SetBool("ReadShapeCompoundMode", True)
+ FreeCAD.Console.PrintError("enabling ReadShapeCompoundMode -> Simplified Mode" + "\n")
-FreeCADGui.addCommand('ksuToolsStepImportModeSTD',ksuToolsStepImportModeSTD())
+
+FreeCADGui.addCommand("ksuToolsStepImportModeSTD", ksuToolsStepImportModeSTD())
####
+
class ksuToolsStepImportModeComp:
"ksu tools disable Simplified STEP Import Mode"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'ImportModeSimplified.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsStepImportModeComp","disable Simplified STEP Import Mode") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsStepImportModeComp","ksu tools disable Simplified STEP Import Mode")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "ImportModeSimplified.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsStepImportModeComp", "disable Simplified STEP Import Mode"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsStepImportModeComp", "ksu tools disable Simplified STEP Import Mode"),
+ }
+
def IsActive(self):
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- ReadShapeCompoundMode_status=paramGetVS.GetBool("ReadShapeCompoundMode")
- if ReadShapeCompoundMode_status:
- return True
- else:
- return False
+ ReadShapeCompoundMode_status = paramGetVS.GetBool("ReadShapeCompoundMode")
+ return bool(ReadShapeCompoundMode_status)
def Activated(self):
# do something here...
##ReadShapeCompoundMode
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- ReadShapeCompoundMode_status=paramGetVS.GetBool("ReadShapeCompoundMode")
- #sayerr("checking ReadShapeCompoundMode")
- FreeCAD.Console.PrintWarning("ReadShapeCompoundMode status "+str(ReadShapeCompoundMode_status)+'\n')
+ ReadShapeCompoundMode_status = paramGetVS.GetBool("ReadShapeCompoundMode")
+ # sayerr("checking ReadShapeCompoundMode")
+ FreeCAD.Console.PrintWarning("ReadShapeCompoundMode status " + str(ReadShapeCompoundMode_status) + "\n")
if ReadShapeCompoundMode_status:
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- paramGetVS.SetBool("ReadShapeCompoundMode",False)
- FreeCAD.Console.PrintWarning("disabling ReadShapeCompoundMode"+'\n')
- #if not ReadShapeCompoundMode_status:
+ paramGetVS.SetBool("ReadShapeCompoundMode", False)
+ FreeCAD.Console.PrintWarning("disabling ReadShapeCompoundMode" + "\n")
+ # if not ReadShapeCompoundMode_status:
# paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
# paramGetVS.SetBool("ReadShapeCompoundMode",True)
# FreeCAD.Console.PrintError("enabling ReadShapeCompoundMode -> Simplified Mode"+'\n')
-FreeCADGui.addCommand('ksuToolsStepImportModeComp',ksuToolsStepImportModeComp())
+
+FreeCADGui.addCommand("ksuToolsStepImportModeComp", ksuToolsStepImportModeComp())
+
####
class ksuToolsCopyPlacement:
"ksu tools Copy Placement"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Placement_Copy.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsCopyPlacement","Copy Placement 1st to 2nd") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsCopyPlacement","ksu tools Copy Placement 1st to 2nd")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Placement_Copy.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsCopyPlacement", "Copy Placement 1st to 2nd"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsCopyPlacement", "ksu tools Copy Placement 1st to 2nd"),
+ }
+
def IsActive(self):
return True
def Activated(self):
# do something here...
def copy_placement(sel):
- if hasattr(sel[0],'Placement'):
- main_p=sel[0].Placement
+ if hasattr(sel[0], "Placement"):
+ main_p = sel[0].Placement
else:
- FreeCAD.Console.PrintWarning("select TWO objects to copy \'1st placement\' to \'2nd placement\'\n")
+ FreeCAD.Console.PrintWarning("select TWO objects to copy '1st placement' to '2nd placement'\n")
return
for o in sel:
- if hasattr(o,'Placement'):
- o.Placement=main_p
-
+ if hasattr(o, "Placement"):
+ o.Placement = main_p
+
doc = FreeCADGui.ActiveDocument
sel = FreeCADGui.Selection.getSelection()
if not sel:
FreeCAD.Console.PrintError("Select at least two objects!\n")
FreeCAD.Console.PrintMessage("all selected objects will receive first object placement\n")
- elif len(sel)<2:
+ elif len(sel) < 2:
FreeCAD.Console.PrintWarning("Select at least two objects!\n")
FreeCAD.Console.PrintMessage("all selected objects will receive first object placement\n")
else:
@@ -2797,442 +3117,523 @@ def copy_placement(sel):
doc.commitTransaction()
FreeCAD.Console.PrintMessage("Placement copied\n")
-FreeCADGui.addCommand('ksuToolsCopyPlacement',ksuToolsCopyPlacement())
+
+FreeCADGui.addCommand("ksuToolsCopyPlacement", ksuToolsCopyPlacement())
+
####
class ksuToolsColoredClone:
"ksu tools colored Clone object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'CloneYlw.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsColoredClone","Colored Clone") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsColoredClone","Colored Clone object")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "CloneYlw.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsColoredClone", "Colored Clone"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsColoredClone", "Colored Clone object"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
+ sel = FreeCADGui.Selection.getSelection()
+
def mk_str(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.encode('utf-8')
- return input
- else: #py2
- if type(input) == unicode:
- input = input.encode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.encode("utf-8")
+ if type(input) == unicode:
+ return input.encode("utf-8")
+ return input
+
if len(sel) != 1:
- msg="Select one object with Shape to be colored Cloned!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
- else: #sel[0].TypeId != 'PartDesign::Body'):
-
- obj_tocopy=sel[0]
- cp_label=mk_str(obj_tocopy.Label)+u'_cl'
-
+ msg = "Select one object with Shape to be colored Cloned!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
+ else: # sel[0].TypeId != 'PartDesign::Body'):
+ obj_tocopy = sel[0]
+ cp_label = mk_str(obj_tocopy.Label) + "_cl"
+
if hasattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name), "Shape"):
import Draft
+
newObj = Draft.make_clone(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name))
FreeCAD.ActiveDocument.recompute()
- newObj.Label=cp_label
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),'ShapeColor'):# and ('Origin' not in FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).TypeId):
+ newObj.Label = cp_label
+ if hasattr(
+ FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),
+ "ShapeColor",
+ ): # and ('Origin' not in FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).TypeId):
# if 'LinkView' in dir(FreeCADGui):
# FreeCAD.ActiveDocument.ActiveObject.ViewObject.ShapeColor=getattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).getLinkedObject(True).ViewObject,'ShapeColor',FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).ViewObject.ShapeColor)
# FreeCAD.ActiveDocument.ActiveObject.ViewObject.LineColor=getattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).getLinkedObject(True).ViewObject,'LineColor',FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).ViewObject.LineColor)
- #else:
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).ShapeColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),'LineColor'):
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).PointColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),'DiffuseColor'):
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).DiffuseColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),'Transparency'):
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).Transparency
+ # else:
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).ShapeColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "LineColor"):
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).PointColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "DiffuseColor"):
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).DiffuseColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "Transparency"):
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).Transparency
else:
- FreeCAD.Console.PrintWarning('missing copy of color attributes')
+ FreeCAD.Console.PrintWarning("missing copy of color attributes")
FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).Visibility = False
- #FreeCAD.ActiveDocument.recompute()
- #else:
- # FreeCAD.Console.PrintWarning("Select object with a \"Shape\" to be copied!\n")
+ # FreeCAD.ActiveDocument.recompute()
+ # else:
+ # FreeCAD.Console.PrintWarning("Select object with a \"Shape\" to be copied!\n")
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select one object with Shape to be cloned!")
- FreeCAD.Console.PrintWarning("Select one object with Shape to be cloned!\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select one object with Shape to be cloned!")
+ FreeCAD.Console.PrintWarning("Select one object with Shape to be cloned!\n")
+
+
+FreeCADGui.addCommand("ksuToolsColoredClone", ksuToolsColoredClone())
-FreeCADGui.addCommand('ksuToolsColoredClone',ksuToolsColoredClone())
####
class ksuToolsColoredBinder:
"ksu tools colored Binder object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'SubShapeBinderYlw.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsColoredBinder","Colored Binder") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsColoredBinder","Colored Binder object")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "SubShapeBinderYlw.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsColoredBinder", "Colored Binder"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsColoredBinder", "Colored Binder object"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
+ sel = FreeCADGui.Selection.getSelection()
+
def mk_str(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.encode('utf-8')
- return input
- else: #py2
- if type(input) == unicode:
- input = input.encode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.encode("utf-8")
+ if type(input) == unicode:
+ return input.encode("utf-8")
+ return input
+
if len(sel) != 1:
- msg="Select one object with Shape to generate a colored Binder!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
- else: #sel[0].TypeId != 'PartDesign::Body'):
-
- obj_tocopy=sel[0]
- cp_label=mk_str(obj_tocopy.Label)+u'_bnd'
-
+ msg = "Select one object with Shape to generate a colored Binder!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
+ else: # sel[0].TypeId != 'PartDesign::Body'):
+ obj_tocopy = sel[0]
+ cp_label = mk_str(obj_tocopy.Label) + "_bnd"
+
if hasattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name), "Shape"):
- import PartDesignGui
- FreeCADGui.runCommand('PartDesign_SubShapeBinder')
+ FreeCADGui.runCommand("PartDesign_SubShapeBinder")
# newObj = FreeCAD.ActiveDocument.addObject('PartDesign::SubShapeBinder',obj_tocopy.Name)
# newObj.Support = [obj_tocopy]
newObj = FreeCAD.ActiveDocument.ActiveObject
- FreeCADGui.ActiveDocument.getObject(newObj.Name).DrawStyle = u"Dashed"
- FreeCADGui.ActiveDocument.getObject(newObj.Name).DisplayMode = u"Wireframe"
+ FreeCADGui.ActiveDocument.getObject(newObj.Name).DrawStyle = "Dashed"
+ FreeCADGui.ActiveDocument.getObject(newObj.Name).DisplayMode = "Wireframe"
FreeCAD.ActiveDocument.recompute()
- newObj.Label=cp_label
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),'ShapeColor'):# and ('Origin' not in FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).TypeId):
+ newObj.Label = cp_label
+ if hasattr(
+ FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),
+ "ShapeColor",
+ ): # and ('Origin' not in FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).TypeId):
# if 'LinkView' in dir(FreeCADGui):
# FreeCAD.ActiveDocument.ActiveObject.ViewObject.ShapeColor=getattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).getLinkedObject(True).ViewObject,'ShapeColor',FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).ViewObject.ShapeColor)
# FreeCAD.ActiveDocument.ActiveObject.ViewObject.LineColor=getattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).getLinkedObject(True).ViewObject,'LineColor',FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).ViewObject.LineColor)
- #else:
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).ShapeColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),'LineColor'):
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).PointColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),'DiffuseColor'):
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).DiffuseColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),'Transparency'):
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).Transparency
+ # else:
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).ShapeColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "LineColor"):
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).PointColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "DiffuseColor"):
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).DiffuseColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "Transparency"):
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).Transparency
else:
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=60
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
else:
- FreeCAD.Console.PrintWarning('missing copy of color attributes')
- #if hasattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name), "getGlobalPlacement"):
+ FreeCAD.Console.PrintWarning("missing copy of color attributes")
+ # if hasattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name), "getGlobalPlacement"):
# newObj.Placement = FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).getGlobalPlacement()
FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).Visibility = False
- #FreeCAD.ActiveDocument.recompute()
- #else:
- # FreeCAD.Console.PrintWarning("Select object with a \"Shape\" to be copied!\n")
+ # FreeCAD.ActiveDocument.recompute()
+ # else:
+ # FreeCAD.Console.PrintWarning("Select object with a \"Shape\" to be copied!\n")
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select one object with Shape to generate a colored Binder!")
- FreeCAD.Console.PrintWarning("Select one object with Shape to generate a colored Binder!\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select one object with Shape to generate a colored Binder!")
+ FreeCAD.Console.PrintWarning("Select one object with Shape to generate a colored Binder!\n")
+
+
+FreeCADGui.addCommand("ksuToolsColoredBinder", ksuToolsColoredBinder())
-FreeCADGui.addCommand('ksuToolsColoredBinder',ksuToolsColoredBinder())
####
####
class ksuToolsReLinkBinder:
"ksu tools Relink Binder object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'SubShapeBinderRelink.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsReLinkBinder","Relink Binder") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsReLinkBinder","Relink Binder object Select Binder and an Object to be linked")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "SubShapeBinderRelink.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsReLinkBinder", "Relink Binder"),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "ksuToolsReLinkBinder",
+ "Relink Binder object Select Binder and an Object to be linked",
+ ),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
+ sel = FreeCADGui.Selection.getSelection()
+
def mk_str(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.encode('utf-8')
- return input
- else: #py2
- if type(input) == unicode:
- input = input.encode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.encode("utf-8")
+ if type(input) == unicode:
+ return input.encode("utf-8")
+ return input
+
if len(sel) != 2:
- msg="Select the Binder and one object with Shape to ReLink the Binder!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
- else: #sel[0].TypeId != 'PartDesign::Body'):
+ msg = "Select the Binder and one object with Shape to ReLink the Binder!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
+ else: # sel[0].TypeId != 'PartDesign::Body'):
selEx = FreeCADGui.Selection.getSelectionEx("", 0)
- binder=selEx[0]
+ binder = selEx[0]
obj2link = selEx[1]
- #FreeCAD.Console.PrintMessage(obj2link.Object.Name+'.'+obj2link.SubElementNames[0]+'\n')
- if binder.Object.TypeId == 'PartDesign::SubShapeBinder' and hasattr(sel[1], "Shape"):
- # [(, ('Part.Part001.Cylinder.',))]
- #FreeCAD.Console.PrintMessage('here'+obj2link.Object.Name+'.'+obj2link.SubElementNames[0]+'\n')
- binder.Object.BindMode = u"Synchronized"
- binder.Object.Support = [(obj2link.Object,(obj2link.SubElementNames[0],))]
+ # FreeCAD.Console.PrintMessage(obj2link.Object.Name+'.'+obj2link.SubElementNames[0]+'\n')
+ if binder.Object.TypeId == "PartDesign::SubShapeBinder" and hasattr(sel[1], "Shape"):
+ # [(, ('Part.Part001.Cylinder.',))]
+ # FreeCAD.Console.PrintMessage('here'+obj2link.Object.Name+'.'+obj2link.SubElementNames[0]+'\n')
+ binder.Object.BindMode = "Synchronized"
+ binder.Object.Support = [(obj2link.Object, (obj2link.SubElementNames[0],))]
binder.Object.recompute(True)
else:
- msg="Select the Binder and one object with Shape to ReLink the Binder!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
+ msg = "Select the Binder and one object with Shape to ReLink the Binder!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select the Binder and one object with Shape to ReLink the Binder!")
- FreeCAD.Console.PrintWarning("Select the Binder and one object with Shape to ReLink the Binder!\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(
+ None,
+ "Warning",
+ "Select the Binder and one object with Shape to ReLink the Binder!",
+ )
+ FreeCAD.Console.PrintWarning("Select the Binder and one object with Shape to ReLink the Binder!\n")
+
+
+FreeCADGui.addCommand("ksuToolsReLinkBinder", ksuToolsReLinkBinder())
-FreeCADGui.addCommand('ksuToolsReLinkBinder',ksuToolsReLinkBinder())
####
class ksuToolsUnion:
"ksu tools Make Union objects"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Geofeature-Fuse.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsUnion","Fuse objects") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsUnion","Make Union (Fuse) objects")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Geofeature-Fuse.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsUnion", "Fuse objects"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsUnion", "Make Union (Fuse) objects"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- doc=FreeCAD.activeDocument()
+ sel = FreeCADGui.Selection.getSelection()
+ doc = FreeCAD.activeDocument()
+
def mk_str(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.encode('utf-8')
- return input
- else: #py2
- if type(input) == unicode:
- input = input.encode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.encode("utf-8")
+ if type(input) == unicode:
+ return input.encode("utf-8")
+ return input
+
##
- doc.openTransaction('union')
- if len(sel)<1:
- msg="Select one or two objects with Shape to be copied!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
- elif sel[0].TypeId == 'App::Part':
- unionLbl=sel[0].Label+"_"
- unionPlc=sel[0].Placement
+ doc.openTransaction("union")
+ if len(sel) < 1:
+ msg = "Select one or two objects with Shape to be copied!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
+ elif sel[0].TypeId == "App::Part":
+ unionLbl = sel[0].Label + "_"
+ unionPlc = sel[0].Placement
sel[0].ViewObject.Visibility = False
- FreeCAD.activeDocument().addObject("Part::MultiFuse","Fusion")
+ FreeCAD.activeDocument().addObject("Part::MultiFuse", "Fusion")
Fusion = FreeCAD.activeDocument().ActiveObject
- #o_list = sel[0].OutList
+ # o_list = sel[0].OutList
o_list = sel[0].OutListRecursive
FreeCADGui.Selection.clearSelection()
- #print("sel",sel)
+ # print("sel",sel)
for o in o_list:
- #if (hasattr(o, 'Shape')) \
+ # if (hasattr(o, 'Shape')) \
# and ('Axis' not in o.Label and 'Plane' not in o.Label and 'Sketch' not in o.Label):
- if hasattr(o, 'Shape'):
- if o.TypeId == 'App::Link' or o.TypeId == 'Part::Feature' or o.TypeId == 'PartDesign::Body':
- #print (o.Label,o.Name)
+ if hasattr(o, "Shape"):
+ if o.TypeId in {"App::Link", "Part::Feature", "PartDesign::Body"}:
+ # print (o.Label,o.Name)
FreeCADGui.Selection.addSelection(o)
print(o.Label)
- sel=FreeCADGui.Selection.getSelection()
- #print(sel)
- objs_in_doc=FreeCAD.ActiveDocument.Objects
- FreeCADGui.runCommand('ksuToolsDeepCopy',0)
- new_objs_in_doc=FreeCAD.ActiveDocument.Objects
- new_objs=[]
+ sel = FreeCADGui.Selection.getSelection()
+ # print(sel)
+ objs_in_doc = FreeCAD.ActiveDocument.Objects
+ FreeCADGui.runCommand("ksuToolsDeepCopy", 0)
+ new_objs_in_doc = FreeCAD.ActiveDocument.Objects
+ new_objs = []
for o in new_objs_in_doc:
if o not in objs_in_doc:
new_objs.append(o)
Fusion.Shapes = new_objs
- Fusion.Label=unionLbl
- Fusion.Placement=unionPlc
- FreeCAD.ActiveDocument.recompute()
- else: #sel[0].TypeId != 'PartDesign::Body'):
- FreeCAD.activeDocument().addObject("Part::MultiFuse","Fusion")
+ Fusion.Label = unionLbl
+ Fusion.Placement = unionPlc
+ FreeCAD.ActiveDocument.recompute()
+ else: # sel[0].TypeId != 'PartDesign::Body'):
+ FreeCAD.activeDocument().addObject("Part::MultiFuse", "Fusion")
Fusion = FreeCAD.activeDocument().ActiveObject
Fusion.Shapes = sel
FreeCAD.ActiveDocument.recompute()
doc.commitTransaction()
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select at least two objects with Shape to be copied!")
- FreeCAD.Console.PrintWarning("Select at least two objects with Shape to be copied!\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select at least two objects with Shape to be copied!")
+ FreeCAD.Console.PrintWarning("Select at least two objects with Shape to be copied!\n")
+
+
+FreeCADGui.addCommand("ksuToolsUnion", ksuToolsUnion())
-FreeCADGui.addCommand('ksuToolsUnion',ksuToolsUnion())
####
class ksuToolsSimpleCopy:
"ksu tools Simple Copy object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'simple_copy.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsSimpleCopy","Simple Copy") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsSimpleCopy","ksu Simple Copy object")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "simple_copy.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsSimpleCopy", "Simple Copy"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsSimpleCopy", "ksu Simple Copy object"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
+ sel = FreeCADGui.Selection.getSelection()
+
def mk_str(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.encode('utf-8')
- return input
- else: #py2
- if type(input) == unicode:
- input = input.encode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.encode("utf-8")
+ if type(input) == unicode:
+ return input.encode("utf-8")
+ return input
+
##
- if len(sel)<1:
- msg="Select at least one object with Shape to be copied!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
- else: #sel[0].TypeId != 'PartDesign::Body'):
+ if len(sel) < 1:
+ msg = "Select at least one object with Shape to be copied!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
+ else: # sel[0].TypeId != 'PartDesign::Body'):
for obj_tocopy in sel:
- #obj_tocopy=sel[0]
- cp_label=mk_str(obj_tocopy.Label)+u'_sc'
+ # obj_tocopy=sel[0]
+ cp_label = mk_str(obj_tocopy.Label) + "_sc"
if hasattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name), "Shape"):
- FreeCAD.ActiveDocument.addObject('Part::Feature',cp_label).Shape=FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).Shape
+ FreeCAD.ActiveDocument.addObject(
+ "Part::Feature",
+ cp_label,
+ ).Shape = FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).Shape
newObj = FreeCAD.ActiveDocument.ActiveObject
newObjV = FreeCADGui.ActiveDocument.ActiveObject
- newObj.Label=cp_label
- #FreeCAD.Console.PrintMessage(obj_tocopy.Label);FreeCAD.Console.PrintMessage('\n')
- #FreeCAD.Console.PrintMessage(obj_tocopy.TypeId)
- #FreeCAD.Console.PrintMessage(obj_tocopy.OutList)
- #FreeCAD.Console.PrintMessage(obj_tocopy.TypeId);FreeCAD.Console.PrintMessage('\n')
- if obj_tocopy.TypeId == 'App::Part':
+ newObj.Label = cp_label
+ # FreeCAD.Console.PrintMessage(obj_tocopy.Label);FreeCAD.Console.PrintMessage('\n')
+ # FreeCAD.Console.PrintMessage(obj_tocopy.TypeId)
+ # FreeCAD.Console.PrintMessage(obj_tocopy.OutList)
+ # FreeCAD.Console.PrintMessage(obj_tocopy.TypeId);FreeCAD.Console.PrintMessage('\n')
+ if obj_tocopy.TypeId == "App::Part":
for subobj in obj_tocopy.OutList:
- #FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage('\n')
- if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name),'ShapeColor'):# and ('Origin' not in FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).TypeId):
+ # FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage('\n')
+ if hasattr(
+ FreeCADGui.ActiveDocument.getObject(subobj.Name),
+ "ShapeColor",
+ ): # and ('Origin' not in FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).TypeId):
# if 'LinkView' in dir(FreeCADGui):
# FreeCAD.ActiveDocument.ActiveObject.ViewObject.ShapeColor=getattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).getLinkedObject(True).ViewObject,'ShapeColor',FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).ViewObject.ShapeColor)
# FreeCAD.ActiveDocument.ActiveObject.ViewObject.LineColor=getattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).getLinkedObject(True).ViewObject,'LineColor',FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).ViewObject.LineColor)
- #else:
- newObjV.ShapeColor=FreeCADGui.ActiveDocument.getObject(subobj.Name).ShapeColor
- #FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' ShapeColor ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).ShapeColor)+ '\n')
- if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name),'LineColor'):
- #FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' LineColor ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).LineColor)+ '\n')
- newObjV.LineColor=FreeCADGui.ActiveDocument.getObject(subobj.Name).LineColor
- newObjV.PointColor=FreeCADGui.ActiveDocument.getObject(subobj.Name).PointColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name),'DiffuseColor'):
- #FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' DiffuseColor ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).DiffuseColor)+ '\n')
- newObjV.DiffuseColor=FreeCADGui.ActiveDocument.getObject(subobj.Name).DiffuseColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name),'Transparency'):
- #FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' Transparency ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).Transparency)+ '\n')
- newObjV.Transparency=FreeCADGui.ActiveDocument.getObject(subobj.Name).Transparency
- elif hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),'ShapeColor'):# and ('Origin' not in FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).TypeId):
+ # else:
+ newObjV.ShapeColor = FreeCADGui.ActiveDocument.getObject(subobj.Name).ShapeColor
+ # FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' ShapeColor ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).ShapeColor)+ '\n')
+ if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name), "LineColor"):
+ # FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' LineColor ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).LineColor)+ '\n')
+ newObjV.LineColor = FreeCADGui.ActiveDocument.getObject(subobj.Name).LineColor
+ newObjV.PointColor = FreeCADGui.ActiveDocument.getObject(subobj.Name).PointColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name), "DiffuseColor"):
+ # FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' DiffuseColor ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).DiffuseColor)+ '\n')
+ newObjV.DiffuseColor = FreeCADGui.ActiveDocument.getObject(
+ subobj.Name,
+ ).DiffuseColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name), "Transparency"):
+ # FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' Transparency ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).Transparency)+ '\n')
+ newObjV.Transparency = FreeCADGui.ActiveDocument.getObject(
+ subobj.Name,
+ ).Transparency
+ elif hasattr(
+ FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),
+ "ShapeColor",
+ ): # and ('Origin' not in FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).TypeId):
# if 'LinkView' in dir(FreeCADGui):
# FreeCAD.ActiveDocument.ActiveObject.ViewObject.ShapeColor=getattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).getLinkedObject(True).ViewObject,'ShapeColor',FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).ViewObject.ShapeColor)
# FreeCAD.ActiveDocument.ActiveObject.ViewObject.LineColor=getattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).getLinkedObject(True).ViewObject,'LineColor',FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).ViewObject.LineColor)
- #else:
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).ShapeColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),'LineColor'):
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).PointColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),'DiffuseColor'):
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).DiffuseColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name),'Transparency'):
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).Transparency
+ # else:
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).ShapeColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "LineColor"):
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(
+ obj_tocopy.Name,
+ ).PointColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "DiffuseColor"):
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = (
+ FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).DiffuseColor
+ )
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "Transparency"):
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = (
+ FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).Transparency
+ )
else:
- FreeCAD.Console.PrintWarning('missing copy of color attributes')
+ FreeCAD.Console.PrintWarning("missing copy of color attributes")
FreeCAD.ActiveDocument.recompute()
- #else:
- # FreeCAD.Console.PrintWarning("Select object with a \"Shape\" to be copied!\n")
+ # else:
+ # FreeCAD.Console.PrintWarning("Select object with a \"Shape\" to be copied!\n")
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select at least one object with Shape to be copied!")
- FreeCAD.Console.PrintWarning("Select at least one object with Shape to be copied!\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select at least one object with Shape to be copied!")
+ FreeCAD.Console.PrintWarning("Select at least one object with Shape to be copied!\n")
+
+
+FreeCADGui.addCommand("ksuToolsSimpleCopy", ksuToolsSimpleCopy())
-FreeCADGui.addCommand('ksuToolsSimpleCopy',ksuToolsSimpleCopy())
#####
class ksuToolsDeepCopy:
"ksu tools PartDN Copy object"
- __Name__ = 'Deep Copy'
- __Help__ = 'Select a part and launch'
- __Author__ = 'galou_breizh'
+ __Name__ = "Deep Copy"
+ __Help__ = "Select a part and launch"
+ __Author__ = "galou_breizh"
+
+ ###
-###
-
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'deep_copy.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsDeepCopy","PartDN Copy") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsDeepCopy","ksu PartDN Copy object\nwith relative placement\n[flattened model]")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "deep_copy.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsDeepCopy", "PartDN Copy"),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "ksuToolsDeepCopy",
+ "ksu PartDN Copy object\nwith relative placement\n[flattened model]",
+ ),
+ }
+
def IsActive(self):
- if int(float(FreeCAD.Version()[0]))==0 and int(float(FreeCAD.Version()[1]))<=16: #active only for FC>0.16
- return False
- else:
- return True
-
+ return not (
+ int(float(FreeCAD.Version()[0])) == 0 and int(float(FreeCAD.Version()[1])) <= 16
+ ) # active only for FC>0.16
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- if len(sel)!=1 and (sel[0].TypeId == 'App::Part' or sel[0].TypeId == 'PartDesign::Body'):
- msg="Select ONE Part Design Next object\nor one or more objects to be copied!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
+ sel = FreeCADGui.Selection.getSelection()
+ if len(sel) != 1 and (sel[0].TypeId == "App::Part" or sel[0].TypeId == "PartDesign::Body"):
+ msg = "Select ONE Part Design Next object\nor one or more objects to be copied!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
else:
doc = FreeCAD.activeDocument()
- if sel[0].TypeId != 'App::Part' and sel[0].TypeId != 'PartDesign::Body':
+ if sel[0].TypeId != "App::Part" and sel[0].TypeId != "PartDesign::Body":
for o in sel:
- if o.TypeId != 'App::Part' and o.TypeId != 'PartDesign::Body':
- copy_subobject(doc,o,'copy')
+ if o.TypeId not in {"App::Part", "PartDesign::Body"}:
+ copy_subobject(doc, o, "copy")
else:
- deep_copy(doc,'flat','copy')
- FreeCADGui.ActiveDocument.getObject(sel[0].Name).Visibility=False
+ deep_copy(doc, "flat", "copy")
+ FreeCADGui.ActiveDocument.getObject(sel[0].Name).Visibility = False
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select ONE Part Design Next object\nor one or more objects to be copied!")
- FreeCAD.Console.PrintWarning("Select ONE Part Design Next object\nor one or more objects to be copied!\n")
-
-FreeCADGui.addCommand('ksuToolsDeepCopy',ksuToolsDeepCopy())
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(
+ None,
+ "Warning",
+ "Select ONE Part Design Next object\nor one or more objects to be copied!",
+ )
+ FreeCAD.Console.PrintWarning("Select ONE Part Design Next object\nor one or more objects to be copied!\n")
+
+
+FreeCADGui.addCommand("ksuToolsDeepCopy", ksuToolsDeepCopy())
+
+
#####
def mk_str_u(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.encode('utf-8')
- return input
- else: #py2
- if type(input) == unicode:
- input = input.encode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.encode("utf-8")
+ if type(input) == unicode:
+ return input.encode("utf-8")
+ return input
+
+
###
make_compound = False
@@ -3242,69 +3643,67 @@ def mk_str_u(input):
# from FreeCAD import gui
-def deep_copy(doc,compound='flat',suffix='(copy)'):
- #FreeCAD.Console.PrintMessage(compound)
+def deep_copy(doc, compound="flat", suffix="(copy)"):
+ # FreeCAD.Console.PrintMessage(compound)
for sel_object in FreeCADGui.Selection.getSelectionEx():
- pName=deep_copy_part(doc, sel_object.Object, compound,suffix)
+ pName = deep_copy_part(doc, sel_object.Object, compound, suffix)
return pName
-def deep_copy_part(doc, part, compound='flat',suffix='(copy)'):
- if part.TypeId != 'App::Part' and part.TypeId != 'PartDesign::Body':
+
+def deep_copy_part(doc, part, compound="flat", suffix="(copy)"):
+ if part.TypeId not in {"App::Part", "PartDesign::Body"}:
# Part is not a part, return.
- return
-
- #FreeCAD.Console.PrintWarning(compound)
- make_compound=compound
+ return None
+
+ # FreeCAD.Console.PrintWarning(compound)
+ make_compound = compound
copied_subobjects = []
copied_subobjects_Names = []
- #print (get_all_subobjects(part))
+ # print (get_all_subobjects(part))
for o in get_all_subobjects(part):
- if o.Name not in copied_subobjects_Names:
- if FreeCADGui.ActiveDocument.getObject(o.Name).Visibility:
- vis=True
- for Container in o.InListRecursive:
- if not (FreeCADGui.ActiveDocument.getObject(Container.Name).Visibility):
- vis=False
- if vis:
- copied_subobjects_Names.append(o.Name)
- copied_subobjects += copy_subobject(doc, o,suffix)
- copied_subobjects_Names.append(o.Name)
- if doc.ActiveObject is not None:
- pName = doc.ActiveObject.Name
- else:
- pName= 'None'
-
- if make_compound=='compound':
- compound = doc.addObject('Part::Compound', mk_str_u(part.Label)+suffix)
+ if o.Name not in copied_subobjects_Names and FreeCADGui.ActiveDocument.getObject(o.Name).Visibility:
+ vis = True
+ for Container in o.InListRecursive:
+ if not (FreeCADGui.ActiveDocument.getObject(Container.Name).Visibility):
+ vis = False
+ if vis:
+ copied_subobjects_Names.append(o.Name)
+ copied_subobjects += copy_subobject(doc, o, suffix)
+ copied_subobjects_Names.append(o.Name)
+ pName = doc.ActiveObject.Name if doc.ActiveObject is not None else "None"
+
+ if make_compound == "compound":
+ compound = doc.addObject("Part::Compound", mk_str_u(part.Label) + suffix)
compound.Links = copied_subobjects
if 0:
- o=copied_subobjects[0]
- print('here',oo.Name,oo.Label)
- if o.Name.startswith('Link'):
- oo=o.LinkedObject
- print(oo.Name,oo.Label)
+ o = copied_subobjects[0]
+ print("here", oo.Name, oo.Label)
+ if o.Name.startswith("Link"):
+ oo = o.LinkedObject
+ print(oo.Name, oo.Label)
compound.ViewObject.ShapeAppearance = oo.ViewObject.ShapeAppearance
pName = doc.ActiveObject.Name
- elif make_compound=='part':
- doc.addObject('App::Part',mk_str_u(part.Label)+'_')
- #FreeCAD.Console.PrintMessage(doc.ActiveObject.Label)
- actobj=doc.ActiveObject
+ elif make_compound == "part":
+ doc.addObject("App::Part", mk_str_u(part.Label) + "_")
+ # FreeCAD.Console.PrintMessage(doc.ActiveObject.Label)
+ actobj = doc.ActiveObject
for uplvlobj in actobj.InListRecursive:
- if uplvlobj.TypeId=='App::Part':
- pName=uplvlobj.Name
- #pName=doc.ActiveObject.Name
+ if uplvlobj.TypeId == "App::Part":
+ pName = uplvlobj.Name
+ # pName=doc.ActiveObject.Name
for obj in copied_subobjects:
- #doc.getObject(pName).addObject(doc.getObject(obj.Name))
- #FreeCAD.Console.PrintMessage(doc.getObject(pName))
- #FreeCAD.Console.PrintMessage(doc.getObject(obj.Name))
+ # doc.getObject(pName).addObject(doc.getObject(obj.Name))
+ # FreeCAD.Console.PrintMessage(doc.getObject(pName))
+ # FreeCAD.Console.PrintMessage(doc.getObject(obj.Name))
doc.getObject(pName).addObject(doc.getObject(obj.Name))
- #FreeCAD.Console.PrintMessage(doc.ActiveObject.Label)
+ # FreeCAD.Console.PrintMessage(doc.ActiveObject.Label)
doc.recompute()
return pName
+
def get_all_subobjects(o):
"""Recursively get all subobjects
-
+
Subobjects of objects having a Shape attribute are not included otherwise each
single feature of the object would be copied. The result is that bodies,
compounds, and the result of boolean operations will be converted into a
@@ -3318,21 +3717,20 @@ def get_all_subobjects(o):
v = stack.pop(0)
if v not in discovered:
discovered.append(v)
- if not hasattr(v, 'Shape'):
+ if not hasattr(v, "Shape"):
stack += v.OutList
return discovered
-
def get_all_subobjects_old(o):
"""Recursively get all subobjects
-
+
Subobjects of objects having a Shape attribute are not included otherwise each
single feature of the object would be copied. The result is that bodies,
compounds, and the result of boolean operations will be converted into a
simple copy of their shape.
"""
- if hasattr(o, 'Shape'):
+ if hasattr(o, "Shape"):
return []
# With the assumption that the attribute InList is ordered, only add the
# subobject if o is the direct parent, i.e. the first in InList.
@@ -3342,20 +3740,20 @@ def get_all_subobjects_old(o):
return l
-def copy_subobject(doc, o,suffix='(copy)'):
+def copy_subobject(doc, o, suffix="(copy)"):
copied_object = []
- if not hasattr(o, 'Shape') or o.TypeId == 'Sketcher::SketchObject' or o.Shape.isNull():
+ if not hasattr(o, "Shape") or o.TypeId == "Sketcher::SketchObject" or o.Shape.isNull():
return copied_object
vo_o = o.ViewObject
try:
- copy = doc.addObject('Part::Feature', o.Name + '_Shape')
+ copy = doc.addObject("Part::Feature", o.Name + "_Shape")
copy.Shape = o.Shape
- #copy.Label = 'Copy of ' + o.Label
- if suffix=='_':
- copy.Label = mk_str_u(o.Label)+suffix
+ # copy.Label = 'Copy of ' + o.Label
+ if suffix == "_":
+ copy.Label = mk_str_u(o.Label) + suffix
else:
- copy.Label = mk_str_u(o.Label)+'.'+suffix
- #copy.Placement = get_recursive_inverse_placement(o).inverse()
+ copy.Label = mk_str_u(o.Label) + "." + suffix
+ # copy.Placement = get_recursive_inverse_placement(o).inverse()
copy.Placement = o.getGlobalPlacement()
vo_copy = copy.ViewObject
@@ -3370,6 +3768,7 @@ def copy_subobject(doc, o,suffix='(copy)'):
copied_object = [copy]
return copied_object
+
def get_recursive_inverse_placement(o):
# We browse the parent in reverse order so we have to multiply the inverse
# placements and return the inverse placement.
@@ -3381,51 +3780,51 @@ def get_recursive_inverse_placement(o):
if parent:
p = p.multiply(get_recursive_inverse_placement(parent))
return p
+
+
##
def toggle_highlight_subtree(objs):
- def addsubobjs(obj,totoggleset):
+ def addsubobjs(obj, totoggleset):
totoggle.add(obj)
for subobj in obj.OutList:
- addsubobjs(subobj,totoggleset)
+ addsubobjs(subobj, totoggleset)
- import FreeCAD
- totoggle=set()
+ totoggle = set()
for obj in objs:
- addsubobjs(obj,totoggle)
- checkinlistcomplete =False
+ addsubobjs(obj, totoggle)
+ checkinlistcomplete = False
while not checkinlistcomplete:
for obj in totoggle:
- if (obj not in objs):
- if (frozenset(obj.InList) - totoggle):
- if hasattr (set, 'totoggle'):
- totoggle.toggle(obj)
- break
+ if (obj not in objs) and (frozenset(obj.InList) - totoggle) and hasattr(set, "totoggle"):
+ totoggle.toggle(obj)
+ break
else:
checkinlistcomplete = True
- obj_tree=objs[1:len(objs)]
+ obj_tree = objs[1 : len(objs)]
for obj in totoggle:
- if 'Compound' not in FreeCADGui.ActiveDocument.getObject(obj.Name).TypeId: # and 'App::Part' not in Gui.ActiveDocument.getObject(obj.Name).TypeId:
- if 'Part' in obj.TypeId or 'App::Link' in obj.TypeId:
+ if (
+ "Compound" not in FreeCADGui.ActiveDocument.getObject(obj.Name).TypeId
+ ): # and 'App::Part' not in Gui.ActiveDocument.getObject(obj.Name).TypeId:
+ if "Part" in obj.TypeId or "App::Link" in obj.TypeId:
if obj not in obj_tree:
FreeCADGui.Selection.addSelection(obj)
else:
FreeCADGui.Selection.removeSelection(obj)
- else:
- if hide_compound==True:
- FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility=False
+ elif hide_compound:
+ FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility = False
+
#####
def toggle_visibility_subtree(objs):
- def addsubobjs(obj,totoggleset):
+ def addsubobjs(obj, totoggleset):
totoggle.add(obj)
for subobj in obj.OutList:
- addsubobjs(subobj,totoggleset)
+ addsubobjs(subobj, totoggleset)
- import FreeCAD
- totoggle=set()
+ totoggle = set()
for obj in objs:
- addsubobjs(obj,totoggle)
- checkinlistcomplete =False
+ addsubobjs(obj, totoggle)
+ checkinlistcomplete = False
while not checkinlistcomplete:
for obj in totoggle:
if (obj not in objs) and (frozenset(obj.InList) - totoggle):
@@ -3434,42 +3833,50 @@ def addsubobjs(obj,totoggleset):
else:
checkinlistcomplete = True
for obj in totoggle:
- if 'Compound' not in FreeCADGui.ActiveDocument.getObject(obj.Name).TypeId:
- if 'Part' in obj.TypeId or 'Sketch' in obj.TypeId:
- #if 'Part::Feature' in obj.TypeId or 'App::Part' in obj.TypeId:
- #if obj.Visibility==True:
- if FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility==True:
- #obj.Document.getObject(obj.Name).Visibility=False
- FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility=False
+ if "Compound" not in FreeCADGui.ActiveDocument.getObject(obj.Name).TypeId:
+ if "Part" in obj.TypeId or "Sketch" in obj.TypeId:
+ # if 'Part::Feature' in obj.TypeId or 'App::Part' in obj.TypeId:
+ # if obj.Visibility==True:
+ if FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility:
+ # obj.Document.getObject(obj.Name).Visibility=False
+ FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility = False
else:
- FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility=True
- else:
- if hide_compound==True:
- FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility=False
+ FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility = True
+ elif hide_compound:
+ FreeCADGui.ActiveDocument.getObject(obj.Name).Visibility = False
+
#####
class ksuToolsRemoveFromTree:
"ksu tools Remove from Tree"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'TreeItemOutMinus.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsRemoveFromTree","Remove from Tree") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsRemoveFromTree","ksu Remove Object(s) from Container Tree\nkeeping Placement\nFirst Selection is the Container")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "TreeItemOutMinus.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsRemoveFromTree", "Remove from Tree"),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "ksuToolsRemoveFromTree",
+ "ksu Remove Object(s) from Container Tree\nkeeping Placement\nFirst Selection is the Container",
+ ),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- doc=FreeCAD.ActiveDocument
- #if "App::Part" in doc.getObject(sel[0].Name).TypeId or "App::LinkGroup" in doc.getObject(sel[0].Name).TypeId:
+ sel = FreeCADGui.Selection.getSelection()
+ doc = FreeCAD.ActiveDocument
+ # if "App::Part" in doc.getObject(sel[0].Name).TypeId or "App::LinkGroup" in doc.getObject(sel[0].Name).TypeId:
if "App::Part" in sel[0].TypeId or "App::LinkGroup" in sel[0].TypeId:
- doc.openTransaction('rmvTree')
- base=doc.getObject(sel[0].Name)
+ doc.openTransaction("rmvTree")
+ base = doc.getObject(sel[0].Name)
for o in sel:
if o.Name != sel[0].Name:
- #o_glob_plac = o.getGlobalPlacement()
+ # o_glob_plac = o.getGlobalPlacement()
if hasattr(base, "OutList"):
if o in base.OutList:
if "App::Part" in o.TypeId:
@@ -3483,93 +3890,122 @@ def Activated(self):
if "App::Part" in item.TypeId:
item.removeObject(o)
elif "App::LinkGroup" in item.TypeId:
- #print(item.Label,o.Label)
+ # print(item.Label,o.Label)
item.ViewObject.dragObject(o)
o.Placement = item.Placement.multiply(o.Placement)
- #o.Placement = o_glob_plac
+ # o.Placement = o_glob_plac
o.Placement = base.Placement.multiply(o.Placement)
for item in base.InListRecursive:
- #fcc_prn(item.Label)
- if item.TypeId == 'App::Part' or item.TypeId == 'PartDesign::Body' or item.TypeId == 'App::LinkGroup':
+ # fcc_prn(item.Label)
+ if item.TypeId in {"App::Part", "PartDesign::Body", "App::LinkGroup"}:
if "App::Part" in item.TypeId:
- #doc.getObject(item.Name).addObject(doc.getObject(o.Name))
+ # doc.getObject(item.Name).addObject(doc.getObject(o.Name))
item.addObject(o)
elif "App::LinkGroup" in item.TypeId:
- #doc.getObject(item.Name).ViewObject.dropObject(doc.getObject(o.Name))
+ # doc.getObject(item.Name).ViewObject.dropObject(doc.getObject(o.Name))
item.ViewObject.dropObject(o)
doc.commitTransaction()
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select one Container and some object(s) to be Removed from the Tree.")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(
+ None,
+ "Warning",
+ "Select one Container and some object(s) to be Removed from the Tree.",
+ )
FreeCAD.Console.PrintWarning("Select one Container and some object(s) to be Removed from the Tree.\n")
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select one Container and some object(s) to be Removed from the Tree.")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(
+ None,
+ "Warning",
+ "Select one Container and some object(s) to be Removed from the Tree.",
+ )
FreeCAD.Console.PrintWarning("Select one Container and some object(s) to be Removed from the Tree.\n")
-
-FreeCADGui.addCommand('ksuToolsRemoveFromTree',ksuToolsRemoveFromTree())
+
+
+FreeCADGui.addCommand("ksuToolsRemoveFromTree", ksuToolsRemoveFromTree())
+
#####
class ksuToolsAddToTree:
"ksu tools Add to Tree"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'TreeItemInPlus.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsAddToTree","Add to Tree") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsAddToTree","ksu Add Object(s) to Container Tree\nkeeping Placement\nFirst Selection is the Container")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "TreeItemInPlus.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsAddToTree", "Add to Tree"),
+ "ToolTip": QT_TRANSLATE_NOOP(
+ "ksuToolsAddToTree",
+ "ksu Add Object(s) to Container Tree\nkeeping Placement\nFirst Selection is the Container",
+ ),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- doc=FreeCAD.ActiveDocument
- #if "App::Part" in doc.getObject(sel[0].Name).TypeId:
+ sel = FreeCADGui.Selection.getSelection()
+ doc = FreeCAD.ActiveDocument
+ # if "App::Part" in doc.getObject(sel[0].Name).TypeId:
if "App::Part" in sel[0].TypeId or "App::LinkGroup" in sel[0].TypeId:
- doc.openTransaction('addTree')
- base=doc.getObject(sel[0].Name)
+ doc.openTransaction("addTree")
+ base = doc.getObject(sel[0].Name)
for o in sel:
if o.Name != sel[0].Name:
if hasattr(base, "OutList"):
for item in base.InListRecursive:
- if item.TypeId == 'App::Part' or item.TypeId == 'PartDesign::Body' or "App::LinkGroup" in item.TypeId:
+ if item.TypeId in {"App::Part", "PartDesign::Body"} or "App::LinkGroup" in item.TypeId:
o.Placement = item.Placement.inverse().multiply(o.Placement)
- #s=o.Shape.copy()
- #Part.show(s)
+ # s=o.Shape.copy()
+ # Part.show(s)
o.Placement = base.Placement.inverse().multiply(o.Placement)
- #s1=o.Shape.copy()
- #Part.show(s1)
+ # s1=o.Shape.copy()
+ # Part.show(s1)
if "App::Part" in sel[0].TypeId:
sel[0].addObject(o)
- #doc.getObject(sel[0].Name).addObject(doc.getObject(o.Name))
+ # doc.getObject(sel[0].Name).addObject(doc.getObject(o.Name))
elif "App::LinkGroup" in sel[0].TypeId:
sel[0].ViewObject.dropObject(o)
doc.commitTransaction()
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select one Container and some object(s) to be Added to the Tree.")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(
+ None,
+ "Warning",
+ "Select one Container and some object(s) to be Added to the Tree.",
+ )
FreeCAD.Console.PrintWarning("Select one Container and some object(s) to be Added to the Tree.\n")
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select one Container and some object(s) to be Added to the Tree.")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(
+ None,
+ "Warning",
+ "Select one Container and some object(s) to be Added to the Tree.",
+ )
FreeCAD.Console.PrintWarning("Select one Container and some object(s) to be Added to the Tree.\n")
-
-FreeCADGui.addCommand('ksuToolsAddToTree',ksuToolsAddToTree())
+
+
+FreeCADGui.addCommand("ksuToolsAddToTree", ksuToolsAddToTree())
+
#####
def toggle_transparency_subtree(objs):
- def addsubobjs(obj,totoggleset):
+ def addsubobjs(obj, totoggleset):
totoggle.add(obj)
for subobj in obj.OutList:
- addsubobjs(subobj,totoggleset)
+ addsubobjs(subobj, totoggleset)
import FreeCAD
- doc=FreeCADGui.ActiveDocument
- totoggle=set()
+
+ doc = FreeCADGui.ActiveDocument
+ totoggle = set()
for obj in objs:
- addsubobjs(obj,totoggle)
- checkinlistcomplete =False
+ addsubobjs(obj, totoggle)
+ checkinlistcomplete = False
while not checkinlistcomplete:
for obj in totoggle:
if (obj not in objs) and (frozenset(obj.InList) - totoggle):
@@ -3577,41 +4013,49 @@ def addsubobjs(obj,totoggleset):
totoggle.toggle(obj)
break
except:
- FreeCAD.Console.PrintWarning('totoggle not allowed\n')
+ FreeCAD.Console.PrintWarning("totoggle not allowed\n")
else:
checkinlistcomplete = True
for obj in totoggle:
- #FreeCAD.Console.PrintMessage(obj.Label)
- #if 'App::Part' not in obj.TypeId and 'Part::Feature' in obj.TypeId:
- if 'App::Part' not in obj.TypeId and 'Part' in obj.TypeId:
- #if obj.Visibility==True:
- #FreeCAD.Console.PrintMessage(obj.Label)
+ # FreeCAD.Console.PrintMessage(obj.Label)
+ # if 'App::Part' not in obj.TypeId and 'Part::Feature' in obj.TypeId:
+ if "App::Part" not in obj.TypeId and "Part" in obj.TypeId:
+ # if obj.Visibility==True:
+ # FreeCAD.Console.PrintMessage(obj.Label)
if doc.getObject(obj.Name).Transparency == 0:
- #obj.Document.getObject(obj.Name).Visibility=False
+ # obj.Document.getObject(obj.Name).Visibility=False
doc.getObject(obj.Name).Transparency = 70
else:
doc.getObject(obj.Name).Transparency = 0
+
+
##
class ksuToolsTransparencyToggle:
"ksu tools Transparency Toggle"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'transparency_toggle.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsTransparencyToggle","Transparency Toggle") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsTransparencyToggle","ksu Selection Transparency Toggle")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "transparency_toggle.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsTransparencyToggle", "Transparency Toggle"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsTransparencyToggle", "ksu Selection Transparency Toggle"),
+ }
+
def IsActive(self):
if FreeCADGui.Selection.getSelection():
return True
-
+ return None
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- doc=FreeCADGui.ActiveDocument
+ sel = FreeCADGui.Selection.getSelection()
+ doc = FreeCADGui.ActiveDocument
for obj in sel:
if "App::Part" not in obj.TypeId and "App::LinkGroup" not in obj.TypeId:
- if hasattr(doc.getObject(obj.Name), 'Transparency'):
+ if hasattr(doc.getObject(obj.Name), "Transparency"):
if doc.getObject(obj.Name).Transparency == 0:
doc.getObject(obj.Name).Transparency = 70
else:
@@ -3619,964 +4063,1204 @@ def Activated(self):
else:
toggle_transparency_subtree(FreeCADGui.Selection.getSelection())
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select one or more object(s) to change its transparency!")
- FreeCAD.Console.PrintWarning("Select one or more object(s) to change its transparency!\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select one or more object(s) to change its transparency!")
+ FreeCAD.Console.PrintWarning("Select one or more object(s) to change its transparency!\n")
-FreeCADGui.addCommand('ksuToolsTransparencyToggle',ksuToolsTransparencyToggle())
+
+FreeCADGui.addCommand("ksuToolsTransparencyToggle", ksuToolsTransparencyToggle())
#####
#####
+
class ksuToolsVisibilityRestore:
"ksu tools Visibility Restore"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'restoreVisibility.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsVisibilityRestore","Show hidden/toggle") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("VisibilityRestore","ksu Show hidden/toggle")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "restoreVisibility.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsVisibilityRestore", "Show hidden/toggle"),
+ "ToolTip": QT_TRANSLATE_NOOP("VisibilityRestore", "ksu Show hidden/toggle"),
+ }
+
def IsActive(self):
- if 1: #FreeCADGui.Selection.getSelection():
+ if 1: # FreeCADGui.Selection.getSelection():
return True
-
+ return None
+
def Activated(self):
global invisible_objs
# do something here...
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- docG=FreeCADGui.ActiveDocument
- doc=FreeCAD.ActiveDocument
- doc.openTransaction('visibilityRestore')
- #if 'invisible_objs' not in globals():
- invisible_objs=[]
- invisible_lbls=[]
+ sel = FreeCADGui.Selection.getSelection()
+ docG = FreeCADGui.ActiveDocument
+ doc = FreeCAD.ActiveDocument
+ doc.openTransaction("visibilityRestore")
+ # if 'invisible_objs' not in globals():
+ invisible_objs = []
+ invisible_lbls = []
for obj in sel:
if "App::Part" not in obj.TypeId and "App::LinkGroup" not in obj.TypeId:
- if hasattr(docG.getObject(obj.Name), 'Visibility'):
- if docG.getObject(obj.Name).Visibility == False:
+ if hasattr(docG.getObject(obj.Name), "Visibility"):
+ if not docG.getObject(obj.Name).Visibility:
docG.getObject(obj.Name).Visibility = True
invisible_objs.append(obj.Name)
# else:
# doc.getObject(obj.Name).Transparency = 0
else:
for o in doc.getObject(obj.Name).OutListRecursive:
- if o.ViewObject.Visibility == False:
- if not(o.Name.startswith('Origin')) and not(o.Name.startswith('Local_CS')) and not('Sketch' in o.Name):
- o.ViewObject.Visibility = True
- invisible_objs.append(o.Name)
- invisible_lbls.append(o.Label)
+ if not o.ViewObject.Visibility and (
+ not (o.Name.startswith("Origin"))
+ and not (o.Name.startswith("Local_CS"))
+ and "Sketch" not in o.Name
+ ):
+ o.ViewObject.Visibility = True
+ invisible_objs.append(o.Name)
+ invisible_lbls.append(o.Label)
FreeCADGui.Selection.clearSelection()
- #print(invisible_objs)
+ # print(invisible_objs)
for nm in invisible_objs:
FreeCADGui.Selection.addSelection(doc.getObject(nm))
print(str(invisible_lbls))
doc.commitTransaction()
else:
- if 'invisible_objs' not in globals():
- invisible_objs=[]
- doc=FreeCAD.ActiveDocument
- doc.openTransaction('visibilityToggle')
+ if "invisible_objs" not in globals():
+ invisible_objs = []
+ doc = FreeCAD.ActiveDocument
+ doc.openTransaction("visibilityToggle")
for nm in invisible_objs:
FreeCADGui.Selection.addSelection(doc.getObject(nm))
- o=doc.getObject(nm)
- if o.ViewObject.Visibility == True:
- if not(o.Name.startswith('Origin')) and not(o.Name.startswith('Local_CS')):
+ o = doc.getObject(nm)
+ if o.ViewObject.Visibility:
+ if not (o.Name.startswith("Origin")) and not (o.Name.startswith("Local_CS")):
o.ViewObject.Visibility = False
doc.commitTransaction()
-
-FreeCADGui.addCommand('ksuToolsVisibilityRestore',ksuToolsVisibilityRestore())
+
+
+FreeCADGui.addCommand("ksuToolsVisibilityRestore", ksuToolsVisibilityRestore())
#####
+
##
class ksuToolsHighlightToggle:
"ksu tools Highlight Toggle"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'select_toggle.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsHighlightToggle","Highlight Toggle") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsHighlightToggle","ksu Selection Highlight Toggle")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "select_toggle.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsHighlightToggle", "Highlight Toggle"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsHighlightToggle", "ksu Selection Highlight Toggle"),
+ }
+
def IsActive(self):
if FreeCADGui.Selection.getSelection():
return True
-
+ return None
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
- #if 'LinkView' not in dir(FreeCADGui): #pre a3 Link3 merge
+ # if 'LinkView' not in dir(FreeCADGui): #pre a3 Link3 merge
toggle_highlight_subtree(FreeCADGui.Selection.getSelection())
- #if FreeCADGui.Selection.getSelection():
+ # if FreeCADGui.Selection.getSelection():
# sel=FreeCADGui.Selection.getSelection()
# doc=FreeCADGui.ActiveDocument
# FreeCADGui.runCommand('Std_ToggleVisibility',0)
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select one or more object(s) to be highlighted!")
- FreeCAD.Console.PrintWarning("Select one or more object(s) to be highlighted!\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select one or more object(s) to be highlighted!")
+ FreeCAD.Console.PrintWarning("Select one or more object(s) to be highlighted!\n")
+
+
+FreeCADGui.addCommand("ksuToolsHighlightToggle", ksuToolsHighlightToggle())
-FreeCADGui.addCommand('ksuToolsHighlightToggle',ksuToolsHighlightToggle())
#####
class ksuToolsVisibilityToggle:
"ksu tools Visibility Toggle"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'visibility_toggle.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsVisibilityToggle","Visibility Toggle") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsVisibilityToggle","ksu Selection Visibility Toggle")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "visibility_toggle.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsVisibilityToggle", "Visibility Toggle"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsVisibilityToggle", "ksu Selection Visibility Toggle"),
+ }
+
def IsActive(self):
if FreeCADGui.Selection.getSelection():
return True
-
+ return None
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
- #toggle_visibility_subtree(FreeCADGui.Selection.getSelection())
- FreeCADGui.runCommand('Std_ToggleVisibility',0)
+ # toggle_visibility_subtree(FreeCADGui.Selection.getSelection())
+ FreeCADGui.runCommand("Std_ToggleVisibility", 0)
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select one or more object(s) to toggle visibility!")
- FreeCAD.Console.PrintWarning("Select one or more object(s) to toggle visibility!\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select one or more object(s) to toggle visibility!")
+ FreeCAD.Console.PrintWarning("Select one or more object(s) to toggle visibility!\n")
+
+
+FreeCADGui.addCommand("ksuToolsVisibilityToggle", ksuToolsVisibilityToggle())
-FreeCADGui.addCommand('ksuToolsVisibilityToggle',ksuToolsVisibilityToggle())
#####
class ksuToolsCheckSolid:
"ksu tools Check Solid property"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'ShapeInfo_check.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsCheckSolid","Check Solid property") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsCheckSolid","ksu Check Solid property\nToggle suffix")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "ShapeInfo_check.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsCheckSolid", "Check Solid property"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsCheckSolid", "ksu Check Solid property\nToggle suffix"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
+ sel = FreeCADGui.Selection.getSelection()
+
def mk_str(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.encode('utf-8')
- return input
- else: #py2
- if type(input) == unicode:
- input = input.encode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.encode("utf-8")
+ if type(input) == unicode:
+ return input.encode("utf-8")
+ return input
+
def i_say(msg):
FreeCAD.Console.PrintMessage(msg)
- FreeCAD.Console.PrintMessage('\n')
-
+ FreeCAD.Console.PrintMessage("\n")
+
def i_sayw(msg):
FreeCAD.Console.PrintWarning(msg)
- FreeCAD.Console.PrintWarning('\n')
-
+ FreeCAD.Console.PrintWarning("\n")
+
def i_sayerr(msg):
FreeCAD.Console.PrintError(msg)
- FreeCAD.Console.PrintWarning('\n')
+ FreeCAD.Console.PrintWarning("\n")
+
##
- if len(sel)<1:
- msg="Select one or more object(s) to be checked!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
+ if len(sel) < 1:
+ msg = "Select one or more object(s) to be checked!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
else:
- non_solids=''
- solids=''
+ non_solids = ""
+ solids = ""
for o in sel:
- if hasattr(o,"Shape"):
- if '.[compsolid]' in o.Label or '.[solid]' in o.Label or '.[shell]' in o.Label\
- or '.[compound]' in o.Label or '.[face]' in o.Label:
- o.Label=mk_str(o.Label).replace('.[solid]','').replace('.[shell]','').replace('.[compsolid]','').replace('.[compound]','').replace('.[face]','')
+ if hasattr(o, "Shape"):
+ if (
+ ".[compsolid]" in o.Label
+ or ".[solid]" in o.Label
+ or ".[shell]" in o.Label
+ or ".[compound]" in o.Label
+ or ".[face]" in o.Label
+ ):
+ o.Label = (
+ mk_str(o.Label)
+ .replace(".[solid]", "")
+ .replace(".[shell]", "")
+ .replace(".[compsolid]", "")
+ .replace(".[compound]", "")
+ .replace(".[face]", "")
+ )
else:
- if len(o.Shape.Solids)>0:
- i_say(mk_str(o.Label)+' Solid object(s) NBR : '+str(len(o.Shape.Solids)))
- solids+=mk_str(o.Label)+'
'
- if '.[solid]' not in o.Label:
- o.Label=mk_str(o.Label)+'.[solid]'
+ if len(o.Shape.Solids) > 0:
+ i_say(mk_str(o.Label) + " Solid object(s) NBR : " + str(len(o.Shape.Solids)))
+ solids += mk_str(o.Label) + "
"
+ if ".[solid]" not in o.Label:
+ o.Label = mk_str(o.Label) + ".[solid]"
else:
- i_sayerr(mk_str(o.Label)+' object is a NON Solid')
- non_solids+=mk_str(o.Label)+'
'
- if len(o.Shape.Shells)>0:
- i_say(mk_str(o.Label)+' Shell object(s) NBR : '+str(len(o.Shape.Shells)))
- if '.[shell]' not in o.Label and '.[solid]' not in o.Label:
- o.Label=mk_str(o.Label)+'.[shell]'
- if len(o.Shape.Compounds)>0:
- i_say(mk_str(o.Label)+' Compound object(s) NBR : '+str(len(o.Shape.Compounds)))
- if '.[compound]' not in o.Label and '.[solid]' not in o.Label and '.[shell]' not in o.Label:
- o.Label=mk_str(o.Label)+'.[compound]'
- if len(o.Shape.CompSolids)>0:
- i_say(mk_str(o.Label)+' CompSolids object(s) NBR : '+str(len(o.Shape.CompSolids)))
- if '.[compsolid]' not in o.Label and '.[solid]' not in o.Label and '.[shell]' not in o.Label\
- and '.[compound]' not in o.Label:
- o.Label=mk_str(o.Label)+'.[compsolid]'
- if len(o.Shape.Faces)>0:
- i_say(mk_str(o.Label)+' Faces object(s) NBR : '+str(len(o.Shape.Faces)))
- if '.[compsolid]' not in o.Label and '.[solid]' not in o.Label and '.[shell]' not in o.Label\
- and '.[compound]' not in o.Label and '.[face]' not in o.Label:
- o.Label=mk_str(o.Label)+'.[face]'
+ i_sayerr(mk_str(o.Label) + " object is a NON Solid")
+ non_solids += mk_str(o.Label) + "
"
+ if len(o.Shape.Shells) > 0:
+ i_say(mk_str(o.Label) + " Shell object(s) NBR : " + str(len(o.Shape.Shells)))
+ if ".[shell]" not in o.Label and ".[solid]" not in o.Label:
+ o.Label = mk_str(o.Label) + ".[shell]"
+ if len(o.Shape.Compounds) > 0:
+ i_say(mk_str(o.Label) + " Compound object(s) NBR : " + str(len(o.Shape.Compounds)))
+ if (
+ ".[compound]" not in o.Label
+ and ".[solid]" not in o.Label
+ and ".[shell]" not in o.Label
+ ):
+ o.Label = mk_str(o.Label) + ".[compound]"
+ if len(o.Shape.CompSolids) > 0:
+ i_say(mk_str(o.Label) + " CompSolids object(s) NBR : " + str(len(o.Shape.CompSolids)))
+ if (
+ ".[compsolid]" not in o.Label
+ and ".[solid]" not in o.Label
+ and ".[shell]" not in o.Label
+ and ".[compound]" not in o.Label
+ ):
+ o.Label = mk_str(o.Label) + ".[compsolid]"
+ if len(o.Shape.Faces) > 0:
+ i_say(mk_str(o.Label) + " Faces object(s) NBR : " + str(len(o.Shape.Faces)))
+ if (
+ ".[compsolid]" not in o.Label
+ and ".[solid]" not in o.Label
+ and ".[shell]" not in o.Label
+ and ".[compound]" not in o.Label
+ and ".[face]" not in o.Label
+ ):
+ o.Label = mk_str(o.Label) + ".[face]"
else:
- FreeCAD.Console.PrintWarning("Select object with a \"Shape\" to be checked!\n")
+ FreeCAD.Console.PrintWarning('Select object with a "Shape" to be checked!\n')
# if len (non_solids)>0:
# reply = QtGui.QMessageBox.information(None,"Warning", 'List of NON Solid object(s):
'+non_solids)
# if len (solids)>0:
# reply = QtGui.QMessageBox.information(None,"Info", 'List of Solid object(s):
'+solids)
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select one or more object(s) to be checked!")
- FreeCAD.Console.PrintWarning("Select one or more object(s) to be checked!\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select one or more object(s) to be checked!")
+ FreeCAD.Console.PrintWarning("Select one or more object(s) to be checked!\n")
+
+
+FreeCADGui.addCommand("ksuToolsCheckSolid", ksuToolsCheckSolid())
-FreeCADGui.addCommand('ksuToolsCheckSolid',ksuToolsCheckSolid())
#####
def toggleAlly(tree, item, collapse):
- if collapse == False:
+ if not collapse:
tree.expandItem(item)
- elif collapse == True:
+ elif collapse:
tree.collapseItem(item)
for i in range(item.childCount()):
print(item.child(i).text(0))
- if 'Origin' not in item.child(i).text(0):
+ if "Origin" not in item.child(i).text(0):
toggleAlly(tree, item.child(i), collapse)
+
+
##
class ksuToolsToggleTreeView:
"ksu tools Toggle Tree View"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'expand_all.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsToggleTreeView","Expand/Collapse Tree View") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsToggleTreeView","ksu tools Expand/Collapse Tree View")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "expand_all.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsToggleTreeView", "Expand/Collapse Tree View"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsToggleTreeView", "ksu tools Expand/Collapse Tree View"),
+ }
+
def IsActive(self):
return True
-
+
def Activated(self):
# do something here...
if FreeCADGui.Selection.getSelection():
##
- sel=FreeCADGui.Selection.getSelection()
+ sel = FreeCADGui.Selection.getSelection()
##
- if len(sel)!=1:
- msg="Select one expandable tree object to be expanded/compressed!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
+ if len(sel) != 1:
+ msg = "Select one expandable tree object to be expanded/compressed!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
else:
- import expTree;reload_lib(expTree)
+ import expTree
+
+ reload_lib(expTree)
expTree.toggle_Tree()
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select one expandable tree object to be expanded/compressed!")
- FreeCAD.Console.PrintWarning("Select one expandable tree object to be expanded/compressed!\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(
+ None,
+ "Warning",
+ "Select one expandable tree object to be expanded/compressed!",
+ )
+ FreeCAD.Console.PrintWarning("Select one expandable tree object to be expanded/compressed!\n")
+
+
+FreeCADGui.addCommand("ksuToolsToggleTreeView", ksuToolsToggleTreeView())
-FreeCADGui.addCommand('ksuToolsToggleTreeView',ksuToolsToggleTreeView())
#####
class ksuToolsAligner:
"ksu tools Aligner"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsAligner","Manipulator tools \'Aligner\'")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Align.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsAligner", "Manipulator tools 'Aligner'")
+ return {
+ "Pixmap": os.path.join(ksuWB_icons_path, "Align.svg"), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
- combined_path = '\t'.join(sys.path)
- if 'Manipulator' in combined_path:
+ combined_path = "\t".join(sys.path)
+ if "Manipulator" in combined_path:
return True
- #else:
+ return None
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
- combined_path = '\t'.join(sys.path)
- if 'Manipulator' in combined_path:
- import Aligner;reload_lib(Aligner)
+ combined_path = "\t".join(sys.path)
+ if "Manipulator" in combined_path:
+ import Aligner
+
+ reload_lib(Aligner)
+
+
+FreeCADGui.addCommand("ksuToolsAligner", ksuToolsAligner())
-FreeCADGui.addCommand('ksuToolsAligner',ksuToolsAligner())
#####
class ksuToolsMover:
"ksu tools Mover"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsMover","Manipulator tools \'Mover\'")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Mover.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsMover", "Manipulator tools 'Mover'")
+ return {
+ "Pixmap": os.path.join(ksuWB_icons_path, "Mover.svg"), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
- combined_path = '\t'.join(sys.path)
- if 'Manipulator' in combined_path:
+ combined_path = "\t".join(sys.path)
+ if "Manipulator" in combined_path:
return True
- #else:
+ return None
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
- combined_path = '\t'.join(sys.path)
- if 'Manipulator' in combined_path:
- import Mover;reload_lib(Mover)
+ combined_path = "\t".join(sys.path)
+ if "Manipulator" in combined_path:
+ import Mover
+
+ reload_lib(Mover)
+
+
+FreeCADGui.addCommand("ksuToolsMover", ksuToolsMover())
+
-FreeCADGui.addCommand('ksuToolsMover',ksuToolsMover())
#####
class ksuToolsCaliper:
"ksu tools Caliper"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsCaliper","Manipulator tools \'Caliper\'")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Caliper.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsCaliper", "Manipulator tools 'Caliper'")
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Caliper.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
- combined_path = '\t'.join(sys.path)
- if 'Manipulator' in combined_path:
+ combined_path = "\t".join(sys.path)
+ if "Manipulator" in combined_path:
return True
- #else:
+ return None
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
- combined_path = '\t'.join(sys.path)
- if 'Manipulator' in combined_path:
- import Caliper;reload_lib(Caliper)
+ combined_path = "\t".join(sys.path)
+ if "Manipulator" in combined_path:
+ import Caliper
+
+ reload_lib(Caliper)
+
+
+FreeCADGui.addCommand("ksuToolsCaliper", ksuToolsCaliper())
+
-FreeCADGui.addCommand('ksuToolsCaliper',ksuToolsCaliper())
#####
class ksuToolsLoopSelection:
"ksu tools Loop Selection"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsLoopSelection","ksu tools \'LoopSelection\'\nLoop selection on a xy outline")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Path-SelectLoop.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP(
+ "ksuToolsLoopSelection",
+ "ksu tools 'LoopSelection'\nLoop selection on a xy outline",
+ )
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Path-SelectLoop.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def __init__(self):
self.obj = None
self.sub = []
self.active = False
def IsActive(self):
- if bool(FreeCADGui.Selection.getSelection()) is False:
- return False
- return True
-
+ return bool(FreeCADGui.Selection.getSelection()) is not False
+
def Activated(self):
try:
sel = FreeCADGui.Selection.getSelectionEx()[0]
PathCommands._CommandSelectLoop.Activated(sel)
except:
- print('Path WB not working')
-
+ print("Path WB not working")
+
+
if FreeCAD.GuiUp:
- FreeCADGui.addCommand('ksuToolsLoopSelection',ksuToolsLoopSelection())
+ FreeCADGui.addCommand("ksuToolsLoopSelection", ksuToolsLoopSelection())
##
#####
class ksuToolsMergeSketches:
"ksu tools Merge Sketches"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsMergeSketches","Merge Sketches")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Sketcher_MergeSketch.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsMergeSketches", "Merge Sketches")
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Sketcher_MergeSketch.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
- combined_path = '\t'.join(sys.path)
+ "\t".join(sys.path)
if FreeCADGui.Selection.getSelection():
return True
- #else:
+ return None
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
- FreeCADGui.runCommand('Sketcher_MergeSketches')
+ FreeCADGui.runCommand("Sketcher_MergeSketches")
for s in FreeCADGui.Selection.getSelection():
- FreeCADGui.ActiveDocument.getObject(s.Name).Visibility=False
-
-FreeCADGui.addCommand('ksuToolsMergeSketches',ksuToolsMergeSketches())
+ FreeCADGui.ActiveDocument.getObject(s.Name).Visibility = False
+
+
+FreeCADGui.addCommand("ksuToolsMergeSketches", ksuToolsMergeSketches())
+
+
###
class ksuToolsEditPrefs:
"ksu tools Edit Preferences"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsEditPrefs","Edit Preferences")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Preferences-Edit.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsEditPrefs", "Edit Preferences")
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Preferences-Edit.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
return True
- #else:
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
- #import kicadStepUptools
+ # import kicadStepUptools
# import hlp
# reload_lib(hlp)
FreeCADGui.showPreferences("kicadStepUpGui")
-
-FreeCADGui.addCommand('ksuToolsEditPrefs',ksuToolsEditPrefs())
+
+
+FreeCADGui.addCommand("ksuToolsEditPrefs", ksuToolsEditPrefs())
+
#####
###
class ksuOpDXF:
"ksu tools open Legacy DXF"
-
+
def GetResources(self):
mybtn_tooltip = QT_TRANSLATE_NOOP("ksuOpDXF", "open Legacy DXF")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'openDXF.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip+' v1.4.0'}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "openDXF.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip + " v1.4.0",
+ }
+
def IsActive(self):
return True
- #else:
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
- #import kicadStepUptools
+ # import kicadStepUptools
# import hlp
# reload_lib(hlp)
- #FreeCADGui.showPreferences("kicadStepUpGui")
-
- import _DXF_Import
+ # FreeCADGui.showPreferences("kicadStepUpGui")
+
import os
- from kicadStepUptools import make_unicode, make_string
+
+ import _DXF_Import
+ from kicadStepUptools import make_string
+
# _DXF_Import.open('D:/Temp/t4k3-DWG.DXF')
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
last_pcb_path = prefs_.GetString("last_pcb_path")
- if not(prefs_.GetBool('not_native_dlg')):
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open a DXF file...",
- last_pcb_path, filter="*.dxf *.DXF")
+ if not (prefs_.GetBool("not_native_dlg")):
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open a DXF file...",
+ last_pcb_path,
+ filter="*.dxf *.DXF",
+ )
else:
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open a DXF file...",
- last_pcb_path, filter="*.dxf *.DXF",options=QtWidgets.QFileDialog.DontUseNativeDialog)
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open a DXF file...",
+ last_pcb_path,
+ filter="*.dxf *.DXF",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
# fname, fnamefilter = QtGui.QFileDialog.getOpenFileName(parent=FreeCADGui.getMainWindow(), caption='Read a DXF file', filter='*.dxf *.DXF')
if name:
- last_pcb_path=os.path.dirname(name)
+ last_pcb_path = os.path.dirname(name)
prefs_.SetString("last_pcb_path", make_string(last_pcb_path))
_DXF_Import.read(name)
FreeCADGui.SendMsgToActiveView("ViewFit")
-
-FreeCADGui.addCommand('ksuOpDXF',ksuOpDXF())
+
+
+FreeCADGui.addCommand("ksuOpDXF", ksuOpDXF())
+
###
class ksuOpEzDXF:
"ksu tools open ezDXF"
-
+
def GetResources(self):
mybtn_tooltip = QT_TRANSLATE_NOOP("ksuOpEzDXF", "open ezDXF")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'openEzDXF.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip }
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "openEzDXF.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
return True
- #else:
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
- #import kicadStepUptools
+ # import kicadStepUptools
# import hlp
# reload_lib(hlp)
- #FreeCADGui.showPreferences("kicadStepUpGui")
+ # FreeCADGui.showPreferences("kicadStepUpGui")
from ezDXF_import import open_ezdxf
+
try:
- import ezdxf
import os
- from kicadStepUptools import make_unicode, make_string
+
+ from kicadStepUptools import make_string
+
# _DXF_Import.open('D:/Temp/t4k3-DWG.DXF')
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
last_pcb_path = prefs_.GetString("last_pcb_path")
- if not(prefs_.GetBool('not_native_dlg')):
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open a DXF file (w ezDXF lib)...",
- last_pcb_path, filter="*.dxf *.DXF")
+ if not (prefs_.GetBool("not_native_dlg")):
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open a DXF file (w ezDXF lib)...",
+ last_pcb_path,
+ filter="*.dxf *.DXF",
+ )
else:
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open a DXF file (w ezDXF lib)...",
- last_pcb_path, filter="*.dxf *.DXF",options=QtWidgets.QFileDialog.DontUseNativeDialog)
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open a DXF file (w ezDXF lib)...",
+ last_pcb_path,
+ filter="*.dxf *.DXF",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
# fname, fnamefilter = QtGui.QFileDialog.getOpenFileName(parent=FreeCADGui.getMainWindow(), caption='Read a DXF file', filter='*.dxf *.DXF')
if name:
- last_pcb_path=os.path.dirname(name)
+ last_pcb_path = os.path.dirname(name)
prefs_.SetString("last_pcb_path", make_string(last_pcb_path))
- open_ezdxf(name,True,True)
+ open_ezdxf(name, True, True)
FreeCADGui.SendMsgToActiveView("ViewFit")
except:
- FreeCAD.Console.PrintError("ezDXF missing; use: \'pip install ezdxf python lib\'\n")
-
-FreeCADGui.addCommand('ksuOpEzDXF',ksuOpEzDXF())
+ FreeCAD.Console.PrintError("ezDXF missing; use: 'pip install ezdxf python lib'\n")
+
+
+FreeCADGui.addCommand("ksuOpEzDXF", ksuOpEzDXF())
+
+
###
class ksuImpDXF:
"ksu tools import Legacy DXF"
-
+
def GetResources(self):
mybtn_tooltip = QT_TRANSLATE_NOOP("ksuImpDXF", "Import Legacy DXF")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'importDXF.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip+' v1.4.0'}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "importDXF.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip + " v1.4.0",
+ }
+
def IsActive(self):
return True
- #else:
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
- #import kicadStepUptools
+ # import kicadStepUptools
# import hlp
# reload_lib(hlp)
- #FreeCADGui.showPreferences("kicadStepUpGui")
-
+ # FreeCADGui.showPreferences("kicadStepUpGui")
+
+ import os
+
import _DXF_Import
from dxf_parser import _importDXF
- import os
- from kicadStepUptools import make_unicode, make_string
+ from kicadStepUptools import make_string
+
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
last_pcb_path = prefs_.GetString("last_pcb_path")
- if not(prefs_.GetBool('not_native_dlg')):
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Import a DXF file...",
- last_pcb_path, filter="*.dxf *.DXF")
+ if not (prefs_.GetBool("not_native_dlg")):
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Import a DXF file...",
+ last_pcb_path,
+ filter="*.dxf *.DXF",
+ )
else:
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Import a DXF file...",
- last_pcb_path, filter="*.dxf *.DXF",options=QtWidgets.QFileDialog.DontUseNativeDialog)
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Import a DXF file...",
+ last_pcb_path,
+ filter="*.dxf *.DXF",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
# fname, fnamefilter = QtGui.QFileDialog.getOpenFileName(parent=FreeCADGui.getMainWindow(), caption='Read a DXF file', filter='*.dxf *.DXF')
if name:
if FreeCAD.ActiveDocument is not None:
- _importDXF.insert(name,FreeCAD.ActiveDocument.Name)
+ _importDXF.insert(name, FreeCAD.ActiveDocument.Name)
else:
_DXF_Import.read(name)
- last_pcb_path=os.path.dirname(name)
+ last_pcb_path = os.path.dirname(name)
prefs_.SetString("last_pcb_path", make_string(last_pcb_path))
FreeCADGui.SendMsgToActiveView("ViewFit")
-
-FreeCADGui.addCommand('ksuImpDXF',ksuImpDXF())
+
+
+FreeCADGui.addCommand("ksuImpDXF", ksuImpDXF())
###
if 0:
+
class ksuExpDXF:
"ksu tools export Legacy DXF"
-
+
def GetResources(self):
- mybtn_tooltip ="export Legacy DXF"
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'exportDXF.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = "export Legacy DXF"
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "exportDXF.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
return True
- #else:
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
- #import kicadStepUptools
+ # import kicadStepUptools
# import hlp
# reload_lib(hlp)
FreeCADGui.showPreferences("kicadStepUpGui")
-
- FreeCADGui.addCommand('ksuExpDXF',ksuExpDXF())
+
+ FreeCADGui.addCommand("ksuExpDXF", ksuExpDXF())
+
+
#####
class ksuRemoveTimeStamp:
"ksu Remove TimeStamp"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuRemoveTimeStamp","Remove TimeStamp from Labels")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'remove_TimeStamp.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP("ksuRemoveTimeStamp", "Remove TimeStamp from Labels")
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "remove_TimeStamp.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
doc = FreeCAD.ActiveDocument
- if doc is not None:
- if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- if len(sel)==1:
- return True
- #else:
+ if doc is not None and FreeCADGui.Selection.getSelection():
+ sel = FreeCADGui.Selection.getSelection()
+ if len(sel) == 1:
+ return True
+ return None
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# removing TimeStamp ...
- doc = FreeCAD.ActiveDocument
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- if len(sel)!=1:
- msg="Select one tree object to remove its Label TimeStamps!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
+ sel = FreeCADGui.Selection.getSelection()
+ if len(sel) != 1:
+ msg = "Select one tree object to remove its Label TimeStamps!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
else:
- #msgBox = QtGui.QMessageBox()
- #msgBox.setText("This will remove ALL TimeStamps from selection objects.\nIt cannot be ondone.")
- #msgBox.setInformativeText("Do you want to continue?")
- #msgBox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
- #msgBox.setDefaultButton(QtGui.QMessageBox.Cancel)
- ret = QtGui.QMessageBox.warning(None, ("Warning"),
- ("This will remove ALL TimeStamps from selection objects.\nDo you want to continue?"),
- QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel,
- QtGui.QMessageBox.Cancel)
- #ret = msgBox.exec_()
+ # msgBox = QtGui.QMessageBox()
+ # msgBox.setText("This will remove ALL TimeStamps from selection objects.\nIt cannot be ondone.")
+ # msgBox.setInformativeText("Do you want to continue?")
+ # msgBox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
+ # msgBox.setDefaultButton(QtGui.QMessageBox.Cancel)
+ ret = QtGui.QMessageBox.warning(
+ None,
+ ("Warning"),
+ ("This will remove ALL TimeStamps from selection objects.\nDo you want to continue?"),
+ QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel,
+ QtGui.QMessageBox.Cancel,
+ )
+ # ret = msgBox.exec_()
if ret == QtGui.QMessageBox.Ok:
for ob in sel:
- #for o in doc.Objects:
- #print (ob.Name,ob.Label,ob.TypeId)
- if ob.TypeId == 'App::Part' or ob.TypeId == 'App::LinkGroup':
+ # for o in doc.Objects:
+ # print (ob.Name,ob.Label,ob.TypeId)
+ if ob.TypeId in {"App::Part", "App::LinkGroup"}:
o_list = ob.OutListRecursive
for o in o_list:
- #print (o.Label)
- if (hasattr(o, 'Shape')) \
- and ('Axis' not in o.Label and 'Plane' not in o.Label and 'Sketch' not in o.Label):
- if o.Label.rfind('_') < o.Label.rfind('['):
- ts = o.Label[o.Label.rfind('_')+1:o.Label.rfind('[')]
- #print (len(ts))
+ # print (o.Label)
+ if (hasattr(o, "Shape")) and (
+ "Axis" not in o.Label and "Plane" not in o.Label and "Sketch" not in o.Label
+ ):
+ if o.Label.rfind("_") < o.Label.rfind("["):
+ ts = o.Label[o.Label.rfind("_") + 1 : o.Label.rfind("[")]
+ # print (len(ts))
if len(ts) == 8:
- o.Label=o.Label[:o.Label.rfind('_')]+o.Label[o.Label.rfind('['):]
+ o.Label = o.Label[: o.Label.rfind("_")] + o.Label[o.Label.rfind("[") :]
else:
- ts = o.Label[o.Label.rfind('_')+1:]
- #print (len(ts))
+ ts = o.Label[o.Label.rfind("_") + 1 :]
+ # print (len(ts))
if len(ts) == 8:
- o.Label=o.Label[:o.Label.rfind('_')]
- #print (o.Label)
+ o.Label = o.Label[: o.Label.rfind("_")]
+ # print (o.Label)
for o in o_list:
- #if ('App::Link' in o.TypeId):
- if (o.TypeId == 'App::Link'):
+ # if ('App::Link' in o.TypeId):
+ if o.TypeId == "App::Link":
o.Label = o.LinkedObject.Label
- FreeCAD.Console.PrintWarning('removed Time Stamps\n')
+ FreeCAD.Console.PrintWarning("removed Time Stamps\n")
elif ret == QtGui.QMessageBox.Cancel:
- FreeCAD.Console.PrintMessage('Operation Aborted\n')
+ FreeCAD.Console.PrintMessage("Operation Aborted\n")
else:
- msg="Select one tree object to remove its Label TimeStamps!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
+ msg = "Select one tree object to remove its Label TimeStamps!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
+
+
+FreeCADGui.addCommand("ksuRemoveTimeStamp", ksuRemoveTimeStamp())
+
-FreeCADGui.addCommand('ksuRemoveTimeStamp',ksuRemoveTimeStamp())
###
class ksuRemoveSuffix:
"ksu Remove Suffix"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuRemoveSuffix","Remove \'custom\' Suffix from Labels")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'RemoveSuffix.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP("ksuRemoveSuffix", "Remove 'custom' Suffix from Labels")
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "RemoveSuffix.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
doc = FreeCAD.ActiveDocument
- if doc is not None:
- if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- if len(sel)==1:
- return True
+ if doc is not None and FreeCADGui.Selection.getSelection():
+ sel = FreeCADGui.Selection.getSelection()
+ if len(sel) == 1:
+ return True
+ return None
def Activated(self):
# removing TimeStamp ...
- doc = FreeCAD.ActiveDocument
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- if len(sel)!=1:
- msg="Select one tree object to remove its Label Suffix!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
+ sel = FreeCADGui.Selection.getSelection()
+ if len(sel) != 1:
+ msg = "Select one tree object to remove its Label Suffix!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
else:
- import exchangePositions;reload_lib(exchangePositions)
- #msgBox = QtGui.QMessageBox()
- #msgBox.setText("This will remove ALL TimeStamps from selection objects.\nIt cannot be ondone.")
- #msgBox.setInformativeText("Do you want to continue?")
- #msgBox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
- #msgBox.setDefaultButton(QtGui.QMessageBox.Cancel)
- #ret = QtGui.QMessageBox.warning(None, ("Warning"),
+ import exchangePositions
+
+ reload_lib(exchangePositions)
+ # msgBox = QtGui.QMessageBox()
+ # msgBox.setText("This will remove ALL TimeStamps from selection objects.\nIt cannot be ondone.")
+ # msgBox.setInformativeText("Do you want to continue?")
+ # msgBox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
+ # msgBox.setDefaultButton(QtGui.QMessageBox.Cancel)
+ # ret = QtGui.QMessageBox.warning(None, ("Warning"),
# message box
rdlg = exchangePositions.RemoveSuffixDlg()
- #msg_box = QtGui.QMessageBox()
- #msg_box.setWindowTitle("Warning")
- #msg_box.setText("This will remove ALL Suffix \'.stp\', \'.step\' from selection objects.\nDo you want to continue?")
+ # msg_box = QtGui.QMessageBox()
+ # msg_box.setWindowTitle("Warning")
+ # msg_box.setText("This will remove ALL Suffix \'.stp\', \'.step\' from selection objects.\nDo you want to continue?")
##layout = msg_box.layout()
- #msg_box.txtInp = QtGui.QLineEdit()
+ # msg_box.txtInp = QtGui.QLineEdit()
##layout.addWidget(msg_box.txtInp)
- #gl = QtGui.QVBoxLayout()
- #gl.addWidget(msg_box.txtInp)
- #msg_box.setLayout(gl)
- #msg_box.setInformativeText('Informative text.')
- #msg_box.setDetailedText("Detailed text.")
+ # gl = QtGui.QVBoxLayout()
+ # gl.addWidget(msg_box.txtInp)
+ # msg_box.setLayout(gl)
+ # msg_box.setInformativeText('Informative text.')
+ # msg_box.setDetailedText("Detailed text.")
##msg_box.DetailedText.setTextInteractionFlags (QtCore.Qt.TextEditorInteraction) #(QtCore.Qt.NoTextInteraction) # (QtCore.Qt.TextSelectableByMouse)
- #msg_box.setIcon(QtGui.QMessageBox.Critical)
- #msg_box.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
- #msg_box.setDefaultButton(QtGui.QMessageBox.Cancel)
+ # msg_box.setIcon(QtGui.QMessageBox.Critical)
+ # msg_box.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
+ # msg_box.setDefaultButton(QtGui.QMessageBox.Cancel)
#
- #ret = msg_box.exec_()
-
+ # ret = msg_box.exec_()
+
ret = rdlg.exec_()
-
+
# ret = QtGui.QMessageBox.warning(None, ("Warning"),
# ("This will remove ALL Suffix \'.stp\', \'.step\' from selection objects.\nDo you want to continue?"),
# QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel,
# QtGui.QMessageBox.Cancel)
- #ret = msgBox.exec_()
+ # ret = msgBox.exec_()
# print(ret)
# print (rdlg.le.text())
- filtering=rdlg.le.text()
- if ret: # == QtGui.QMessageBox.Ok:
+ filtering = rdlg.le.text()
+ if ret: # == QtGui.QMessageBox.Ok:
for ob in sel:
- #for o in doc.Objects:
- #print (ob.Name,ob.Label,ob.TypeId)
- if ob.TypeId == 'App::Part' or ob.TypeId == 'App::LinkGroup':
- #suffix1 = '.stp';suffix2 = '.step';suffix3 = '_stp';suffix2 = '_step'
- #if ob.Label.lower().endswith(suffix1) or ob.Label.lower().endswith(suffix2)\
+ # for o in doc.Objects:
+ # print (ob.Name,ob.Label,ob.TypeId)
+ if ob.TypeId in {"App::Part", "App::LinkGroup"}:
+ # suffix1 = '.stp';suffix2 = '.step';suffix3 = '_stp';suffix2 = '_step'
+ # if ob.Label.lower().endswith(suffix1) or ob.Label.lower().endswith(suffix2)\
# or ob.Label.lower().endswith(suffix1) or ob.Label.lower().endswith(suffix2):
o_list = ob.OutListRecursive
for o in o_list:
- #print (o.Label)
- if (hasattr(o, 'Shape')) \
- and ('Axis' not in o.Label and 'Plane' not in o.Label and 'Sketch' not in o.Label):
- #suffix1 = '.stp';suffix2 = '.step'
- #if o.Label.lower().endswith(suffix1) or o.Label.lower().endswith(suffix2):
- #o.Label = re.sub(rdlg.le.text()+'$', '', o.Label, flags=re.IGNORECASE)
- #print(o.Label[:o.Label.rfind (filtering)])
- if o.Label.rfind (filtering) != -1:
- o.Label = o.Label[:o.Label.rfind (filtering)]
- #o.Label = re.sub('.stp', '', o.Label, flags=re.IGNORECASE)
- #o.Label = re.sub('.step', '', o.Label, flags=re.IGNORECASE)
- #print (o.Label)
- if o.TypeId == 'App::Part' or o.TypeId == 'App::LinkGroup':
- #o.Label = re.sub(rdlg.le.text()+'$', '', o.Label, flags=re.IGNORECASE)
- fixfiltering = filtering.replace('.','_')
- #print (fixfiltering)
- #print(o.Label[:o.Label.rfind (fixfiltering)])
- if o.Label.rfind (fixfiltering) != -1:
- o.Label = o.Label[:o.Label.rfind (fixfiltering)]
- #o.Label = re.sub('_stp', '', o.Label, flags=re.IGNORECASE)
- #o.Label = re.sub('_step', '', o.Label, flags=re.IGNORECASE)
- #o.Label = re.sub('.stp', '', o.Label, flags=re.IGNORECASE)
- #o.Label = re.sub('.step', '', o.Label, flags=re.IGNORECASE)
+ # print (o.Label)
+ if (hasattr(o, "Shape")) and (
+ "Axis" not in o.Label and "Plane" not in o.Label and "Sketch" not in o.Label
+ ):
+ # suffix1 = '.stp';suffix2 = '.step'
+ # if o.Label.lower().endswith(suffix1) or o.Label.lower().endswith(suffix2):
+ # o.Label = re.sub(rdlg.le.text()+'$', '', o.Label, flags=re.IGNORECASE)
+ # print(o.Label[:o.Label.rfind (filtering)])
+ if o.Label.rfind(filtering) != -1:
+ o.Label = o.Label[: o.Label.rfind(filtering)]
+ # o.Label = re.sub('.stp', '', o.Label, flags=re.IGNORECASE)
+ # o.Label = re.sub('.step', '', o.Label, flags=re.IGNORECASE)
+ # print (o.Label)
+ if o.TypeId in {"App::Part", "App::LinkGroup"}:
+ # o.Label = re.sub(rdlg.le.text()+'$', '', o.Label, flags=re.IGNORECASE)
+ fixfiltering = filtering.replace(".", "_")
+ # print (fixfiltering)
+ # print(o.Label[:o.Label.rfind (fixfiltering)])
+ if o.Label.rfind(fixfiltering) != -1:
+ o.Label = o.Label[: o.Label.rfind(fixfiltering)]
+ # o.Label = re.sub('_stp', '', o.Label, flags=re.IGNORECASE)
+ # o.Label = re.sub('_step', '', o.Label, flags=re.IGNORECASE)
+ # o.Label = re.sub('.stp', '', o.Label, flags=re.IGNORECASE)
+ # o.Label = re.sub('.step', '', o.Label, flags=re.IGNORECASE)
for o in o_list:
- if (o.TypeId == 'App::Link'):
+ if o.TypeId == "App::Link":
o.Label = o.LinkedObject.Label
- FreeCAD.Console.PrintWarning('removed Suffix \''+filtering+'\' \n')
- elif ret == 0: #== QtGui.QMessageBox.Cancel:
- msg='Operation Aborted\n'
+ FreeCAD.Console.PrintWarning("removed Suffix '" + filtering + "' \n")
+ elif ret == 0: # == QtGui.QMessageBox.Cancel:
+ msg = "Operation Aborted\n"
FreeCAD.Console.PrintMessage(msg)
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
else:
- msg="Select one tree object to remove its Label Suffix!\n"
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
- FreeCAD.Console.PrintWarning(msg)
+ msg = "Select one tree object to remove its Label Suffix!\n"
+ QtGui.QMessageBox.information(None, "Warning", msg)
+ FreeCAD.Console.PrintWarning(msg)
+
+
+FreeCADGui.addCommand("ksuRemoveSuffix", ksuRemoveSuffix())
-FreeCADGui.addCommand('ksuRemoveSuffix',ksuRemoveSuffix())
#####
class ksuToolsExplode:
"ksu tools Explode"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsExplode","ksu Tools PCB Explode\nSelect the top container of a KiCad PCB to exlode it")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Explode_Pcb.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP(
+ "ksuToolsExplode",
+ "ksu Tools PCB Explode\nSelect the top container of a KiCad PCB to exlode it",
+ )
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Explode_Pcb.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
- if FreeCAD.ActiveDocument is None:
- return False
- else:
- return True
-
+ return FreeCAD.ActiveDocument is not None
+
def Activated(self):
# do something here...
import explode
+
explode.runExplodeGui()
- #import explode;reload_lib(explode)
+ # import explode;reload_lib(explode)
+
+
+FreeCADGui.addCommand("ksuToolsExplode", ksuToolsExplode())
+
-FreeCADGui.addCommand('ksuToolsExplode',ksuToolsExplode())
#####
class ksuToolsDefeaturingTools:
"ksu tools DefeaturingTools"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsDefeaturingTools","Defeaturing Tools from Defeaturing WorkBench")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'DefeaturingTools.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsDefeaturingTools", "Defeaturing Tools from Defeaturing WorkBench")
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "DefeaturingTools.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
- combined_path = '\t'.join(sys.path)
- if 'Defeaturing' in combined_path:
+ combined_path = "\t".join(sys.path)
+ if "Defeaturing" in combined_path:
return True
- #else:
+ return None
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
- combined_path = '\t'.join(sys.path)
- if 'Defeaturing' in combined_path:
- import DefeaturingTools;reload_lib(DefeaturingTools)
+ combined_path = "\t".join(sys.path)
+ if "Defeaturing" in combined_path:
+ import DefeaturingTools
+
+ reload_lib(DefeaturingTools)
+
+
+FreeCADGui.addCommand("ksuToolsDefeaturingTools", ksuToolsDefeaturingTools())
+
-FreeCADGui.addCommand('ksuToolsDefeaturingTools',ksuToolsDefeaturingTools())
#####
class ksuToolsRemoveSubTree:
"ksu tools Remove Sub Tree"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsRemoveSubTree","Remove Sub Tree")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'RemoveSubtree.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsRemoveSubTree", "Remove Sub Tree")
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "RemoveSubtree.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
if FreeCADGui.Selection.getSelection():
return True
- #else:
+ return None
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
- FreeCAD.ActiveDocument.openTransaction('rmvSubTree')
+ FreeCAD.ActiveDocument.openTransaction("rmvSubTree")
import kicadStepUptools
+
kicadStepUptools.removesubtree(FreeCADGui.Selection.getSelection())
FreeCAD.ActiveDocument.commitTransaction()
-
-FreeCADGui.addCommand('ksuToolsRemoveSubTree',ksuToolsRemoveSubTree())
+
+
+FreeCADGui.addCommand("ksuToolsRemoveSubTree", ksuToolsRemoveSubTree())
+
+
####
class ksuToolsAddTracks:
"ksu tools Add Tracks"
-
- def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsAddTracks","ksu tools Add Tracks\nNB: it could be a very intensive loading!")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'tracks.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ def GetResources(self):
+ mybtn_tooltip = QT_TRANSLATE_NOOP(
+ "ksuToolsAddTracks",
+ "ksu tools Add Tracks\nNB: it could be a very intensive loading!",
+ )
+ return {
+ "Pixmap": os.path.join(ksuWB_icons_path, "tracks.svg"), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
def IsActive(self):
return True
- #else:
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
+ from PySide import QtCore
+
import tracks
- from kicadStepUptools import removesubtree
- from kicadStepUptools import ZoomFitThread
- from kicadStepUptools import restore_specular
- from kicadStepUptools import restore_specular_cls
- from PySide import QtGui, QtCore
- if FreeCAD.ActiveDocument is not None:
- doc = FreeCAD.ActiveDocument
- else:
- doc = FreeCAD.newDocument()
- #doc.commitTransaction()
- #doc.UndoMode = 1
- doc.openTransaction('add_tracks_kicad')
- objs_pre=[]
+ from kicadStepUptools import ZoomFitThread, removesubtree, restore_specular, restore_specular_cls
+
+ doc = FreeCAD.ActiveDocument if FreeCAD.ActiveDocument is not None else FreeCAD.newDocument()
+ # doc.commitTransaction()
+ # doc.UndoMode = 1
+ doc.openTransaction("add_tracks_kicad")
+ objs_pre = []
if doc is not None:
- objs_pre=doc.Objects
+ objs_pre = doc.Objects
add_toberemoved = tracks.addtracks()
if restore_specular_cls:
restore_specular(objs_pre)
# print(add_toberemoved)
doc.commitTransaction()
doc.recompute()
+
def removing_objs():
- ''' removing objects after delay '''
- from kicadStepUptools import removesubtree
- doc.openTransaction('rmv_tracks_kicad')
+ """removing objects after delay"""
+ doc.openTransaction("rmv_tracks_kicad")
for tbr in add_toberemoved:
removesubtree(tbr)
doc.commitTransaction()
# doc.undo()
# doc.undo()
+
# adding a timer to allow double transactions during the python code
- QtCore.QTimer.singleShot(0.2,removing_objs)
- if (not pt_lnx): # and (not pt_osx): issue on AppImages hanging on loading
+ QtCore.QTimer.singleShot(0.2, removing_objs)
+ if not pt_lnx: # and (not pt_osx): issue on AppImages hanging on loading
FreeCADGui.SendMsgToActiveView("ViewFit")
else:
- zf= Timer (0.25,ZoomFitThread)
- zf.start()
+ zf = Timer(0.25, ZoomFitThread)
+ zf.start()
##
-FreeCADGui.addCommand('ksuToolsAddTracks',ksuToolsAddTracks())
+
+FreeCADGui.addCommand("ksuToolsAddTracks", ksuToolsAddTracks())
+
+
#####
class ksuToolsAddSilks:
"ksu tools Add Silks"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("ksuToolsAddSilks","ksu tools Add Silks from KiCad exported DXF\nNB: it could be a very intensive loading!")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Silks.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP(
+ "ksuToolsAddSilks",
+ "ksu tools Add Silks from KiCad exported DXF\nNB: it could be a very intensive loading!",
+ )
+ return {
+ "Pixmap": os.path.join(ksuWB_icons_path, "Silks.svg"), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
return True
- #else:
+ # else:
# self.setToolTip("Grayed Tooltip!")
# print(self.ObjectName)
# grayed_tooltip="Grayed Tooltip!"
# mybtn_tooltip=grayed_tooltip
-
+
def Activated(self):
# do something here...
import makefacedxf
- if FreeCAD.ActiveDocument is not None:
- doc = FreeCAD.ActiveDocument
- else:
- doc = FreeCAD.newDocument()
- if 1: # using internal dxf old legacy library loader makefacedxf.checkDXFsettings():
- doc.openTransaction('add_silks')
+
+ doc = FreeCAD.ActiveDocument if FreeCAD.ActiveDocument is not None else FreeCAD.newDocument()
+ if 1: # using internal dxf old legacy library loader makefacedxf.checkDXFsettings():
+ doc.openTransaction("add_silks")
makefacedxf.makeFaceDXF()
doc.commitTransaction()
else:
@@ -4585,394 +5269,454 @@ def Activated(self):
- DXF Join Geometries
- DXF Create Simple Part Shapes
in DXF Preferences Import options"""
- reply = QtGui.QMessageBox.information(None,"Warning", msg)
+ QtGui.QMessageBox.information(None, "Warning", msg)
+
+
+FreeCADGui.addCommand("ksuToolsAddSilks", ksuToolsAddSilks())
+
-FreeCADGui.addCommand('ksuToolsAddSilks',ksuToolsAddSilks())
#####
class ksuExcDemo:
exFile = None
def __init__(self, exFile):
self.exFile = str(exFile)
- self.ext = self.exFile[self.exFile.rfind('.'):].lower()
- #print self.ext
-
+ self.ext = self.exFile[self.exFile.rfind(".") :].lower()
+ # print self.ext
+
# 'hierarchy_nav.svg' for Demo
#'Pixmap' : os.path.join( ksuWB_icons_path , 'hierarchy_nav.svg') ,
def GetResources(self):
- if 'pdf' in self.ext:
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'datasheet.svg') ,
- 'MenuText': str(self.exFile),
- 'ToolTip' : "Demo files"}
- elif 'kicad_pcb' in self.ext:
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'importPCB.svg'), #'importBoard.svg') ,
- 'MenuText': str(self.exFile),
- 'ToolTip' : "Demo files"}
- elif 'kicad_mod' in self.ext:
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'importFP.svg') ,
- 'MenuText': str(self.exFile),
- 'ToolTip' : "Demo files"}
- elif 'fcstd' in self.ext:
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Freecad.svg') ,
- 'MenuText': str(self.exFile),
- 'ToolTip' : "Demo files"}
- elif 'dxf' in self.ext:
- return {'Pixmap' : os.path.join( ksuWB_icons_path , '2D-frame.svg') ,
- 'MenuText': str(self.exFile),
- 'ToolTip' : "Demo files"}
- elif 'step' in self.ext:
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'importStep.svg') ,
- 'MenuText': str(self.exFile),
- 'ToolTip' : "Demo files"}
- else:
- return {'MenuText': str(self.exFile),
- 'ToolTip' : "Demo files"}
+ if "pdf" in self.ext:
+ return {
+ "Pixmap": os.path.join(ksuWB_icons_path, "datasheet.svg"),
+ "MenuText": str(self.exFile),
+ "ToolTip": "Demo files",
+ }
+ if "kicad_pcb" in self.ext:
+ return {
+ "Pixmap": os.path.join(ksuWB_icons_path, "importPCB.svg"), #'importBoard.svg') ,
+ "MenuText": str(self.exFile),
+ "ToolTip": "Demo files",
+ }
+ if "kicad_mod" in self.ext:
+ return {
+ "Pixmap": os.path.join(ksuWB_icons_path, "importFP.svg"),
+ "MenuText": str(self.exFile),
+ "ToolTip": "Demo files",
+ }
+ if "fcstd" in self.ext:
+ return {
+ "Pixmap": os.path.join(ksuWB_icons_path, "Freecad.svg"),
+ "MenuText": str(self.exFile),
+ "ToolTip": "Demo files",
+ }
+ if "dxf" in self.ext:
+ return {
+ "Pixmap": os.path.join(ksuWB_icons_path, "2D-frame.svg"),
+ "MenuText": str(self.exFile),
+ "ToolTip": "Demo files",
+ }
+ if "step" in self.ext:
+ return {
+ "Pixmap": os.path.join(ksuWB_icons_path, "importStep.svg"),
+ "MenuText": str(self.exFile),
+ "ToolTip": "Demo files",
+ }
+ return {"MenuText": str(self.exFile), "ToolTip": "Demo files"}
def Activated(self):
- FreeCAD.Console.PrintWarning('opening ' + self.exFile + "\r\n")
- import os, sys
+ FreeCAD.Console.PrintWarning("opening " + self.exFile + "\r\n")
+ import os
+ import sys
+
# So we can open the "Open File" dialog
- mw = FreeCADGui.getMainWindow()
+ FreeCADGui.getMainWindow()
# Start off defaulting to the Examples directory
ksu_base_path = ksu_locator.module_path()
- exs_dir_path = os.path.join(ksu_base_path, 'demo')
- abs_ksu_path = ksu_locator.abs_module_path()
+ exs_dir_path = os.path.join(ksu_base_path, "demo")
+ ksu_locator.abs_module_path()
# Append this script's directory to sys.path
sys.path.append(os.path.dirname(exs_dir_path))
# We've created a library that FreeCAD can use as well to open CQ files
- fnameDemo=(os.path.join(exs_dir_path, self.exFile))
- demo_model='dpak-to252.step'
- stepfname=(os.path.join(exs_dir_path, 'shapes',demo_model))
+ fnameDemo = os.path.join(exs_dir_path, self.exFile)
+ demo_model = "dpak-to252.step"
+ stepfname = os.path.join(exs_dir_path, "shapes", demo_model)
ext = os.path.splitext(os.path.basename(fnameDemo))[1]
- nme = os.path.splitext(os.path.basename(fnameDemo))[0]
- FC_majorV=int(float(FreeCAD.Version()[0]))
- FC_minorV=int(float(FreeCAD.Version()[1]))
+ os.path.splitext(os.path.basename(fnameDemo))[0]
+ FC_majorV = int(float(FreeCAD.Version()[0]))
+ FC_minorV = int(float(FreeCAD.Version()[1]))
+
+ if ext.lower() == ".pdf":
+ import subprocess
+ import sys
- if ext.lower()==".pdf":
- import subprocess, sys
if sys.platform == "linux" or sys.platform == "linux2":
- if 'LD_LIBRARY_PATH' in os.environ: # workaround for AppImage
+ if "LD_LIBRARY_PATH" in os.environ: # workaround for AppImage
my_env = os.environ
- ldlp = os.environ['LD_LIBRARY_PATH']
- del my_env['LD_LIBRARY_PATH']
- #print("xdg-open", fnameDemo)
+ os.environ["LD_LIBRARY_PATH"]
+ del my_env["LD_LIBRARY_PATH"]
+ # print("xdg-open", fnameDemo)
subprocess.Popen(["xdg-open", fnameDemo], env=my_env)
else:
subprocess.call(["xdg-open", fnameDemo])
if sys.platform == "darwin":
# osx
- cmd_open = 'open '+fnameDemo
- os.system(cmd_open) #win, osx
+ cmd_open = "open " + fnameDemo
+ os.system(cmd_open) # win, osx
else:
# win
- subprocess.Popen([fnameDemo],shell=True)
- elif ext.lower()==".kicad_pcb" or ext.lower()==".kicad_mod":
- #FreeCAD.Console.PrintMessage(abs_ksu_path + "\r\n")
- #FreeCAD.Console.PrintMessage(stepfname + "\r\n")
- #FreeCAD.Console.PrintMessage(exs_dir_path + "\r\n")
+ subprocess.Popen([fnameDemo], shell=True)
+ elif ext.lower() == ".kicad_pcb" or ext.lower() == ".kicad_mod":
+ # FreeCAD.Console.PrintMessage(abs_ksu_path + "\r\n")
+ # FreeCAD.Console.PrintMessage(stepfname + "\r\n")
+ # FreeCAD.Console.PrintMessage(exs_dir_path + "\r\n")
import kicadStepUptools
+
# reload( kicadStepUptools )
if reload_Gui:
- reload_lib( kicadStepUptools )
- from kicadStepUptools import open, create_axis #onLoadBoard, onLoadFootprint
- if ext.lower()==".kicad_mod":
- dname= (demo_model).split('.')[0].replace('-','_')
+ reload_lib(kicadStepUptools)
+ from kicadStepUptools import create_axis, open # onLoadBoard, onLoadFootprint
+
+ if ext.lower() == ".kicad_mod":
+ dname = (demo_model).split(".", maxsplit=1)[0].replace("-", "_")
doc = FreeCAD.newDocument(dname)
- dname=doc.Name
- #print dname
+ dname = doc.Name
+ # print dname
FreeCAD.setActiveDocument(dname)
- FreeCAD.ActiveDocument=FreeCAD.getDocument(dname)
- FreeCADGui.ActiveDocument=FreeCADGui.getDocument(dname)
- #doc=FreeCAD.newDocument((demo_model).split('.')[0].replace('-','_'))
- #FreeCAD.setActiveDocument(doc)
+ FreeCAD.ActiveDocument = FreeCAD.getDocument(dname)
+ FreeCADGui.ActiveDocument = FreeCADGui.getDocument(dname)
+ # doc=FreeCAD.newDocument((demo_model).split('.')[0].replace('-','_'))
+ # FreeCAD.setActiveDocument(doc)
import ImportGui
- ImportGui.insert(stepfname,doc.Name)
+
+ ImportGui.insert(stepfname, doc.Name)
FreeCADGui.activeDocument().activeView().viewAxonometric()
- open (fnameDemo)
+ open(fnameDemo)
if FreeCAD.ActiveDocument.getObject("axis") is None:
create_axis()
else:
- open (fnameDemo)
- #docL=FreeCAD.ActiveDocument.Label
- elif ext.lower()==".fcstd":
- if FC_majorV==0 and FC_minorV <17:
- fnameDemo=fnameDemo.rstrip(ext)+'-fc16'+ ext
- FreeCAD.Console.PrintWarning('opening ' + fnameDemo + "\r\n")
+ open(fnameDemo)
+ # docL=FreeCAD.ActiveDocument.Label
+ elif ext.lower() == ".fcstd":
+ if FC_majorV == 0 and FC_minorV < 17:
+ fnameDemo = fnameDemo.rstrip(ext) + "-fc16" + ext
+ FreeCAD.Console.PrintWarning("opening " + fnameDemo + "\r\n")
FreeCAD.open(fnameDemo)
- if 'footprint' not in fnameDemo:
+ if "footprint" not in fnameDemo:
FreeCADGui.activeDocument().activeView().viewAxonometric()
- elif ext.lower()==".step":
- if FC_majorV==0 and FC_minorV <17:
- fnameDemo=fnameDemo.rstrip(ext)+'-fc16'+ ext
- FreeCAD.Console.PrintWarning('opening ' + fnameDemo + "\r\n")
+ elif ext.lower() == ".step":
+ if FC_majorV == 0 and FC_minorV < 17:
+ fnameDemo = fnameDemo.rstrip(ext) + "-fc16" + ext
+ FreeCAD.Console.PrintWarning("opening " + fnameDemo + "\r\n")
import ImportGui
+
ImportGui.open(fnameDemo)
FreeCADGui.activeDocument().activeView().viewAxonometric()
FreeCADGui.SendMsgToActiveView("ViewFit")
- elif ext.lower()==".dxf":
- #import ImportGui
+ elif ext.lower() == ".dxf":
+ # import ImportGui
import importDXF
+
importDXF.open(fnameDemo)
- #ImportGui.open(fnameDemo)
- #FreeCADGui.activeDocument().activeView().viewAxonometric()
+ # ImportGui.open(fnameDemo)
+ # FreeCADGui.activeDocument().activeView().viewAxonometric()
FreeCADGui.SendMsgToActiveView("ViewFit")
- #if ext==".pdf":
+ # if ext==".pdf":
# subprocess.Popen([file],shell=True)
-
- #import ImportGui
- #ImportGui.open(os.path.join(exs_dir_path, self.exFile))
- #ImportCQ.open(os.path.join(exs_dir_path, self.exFile))
+
+ # import ImportGui
+ # ImportGui.open(os.path.join(exs_dir_path, self.exFile))
+ # ImportCQ.open(os.path.join(exs_dir_path, self.exFile))
+
##
-class checkSolidExpSTEP():
+class checkSolidExpSTEP:
"ksu tools check Export Step"
-
+
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("checkSolidExpSTEP","Check if the selected part would be\nexported to STEP as a single solid")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Import-Export-STEP.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
-
+ mybtn_tooltip = QT_TRANSLATE_NOOP(
+ "checkSolidExpSTEP",
+ "Check if the selected part would be\nexported to STEP as a single solid",
+ )
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Import-Export-STEP.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
+
def IsActive(self):
if len(FreeCADGui.Selection.getSelection()) == 1:
return True
-
+ return None
+
def Activated(self):
# do something here...
- from PySide import QtGui, QtCore
- import tempfile
-
- doc=FreeCAD.ActiveDocument
+ from PySide import QtGui
+
+ doc = FreeCAD.ActiveDocument
docG = FreeCADGui.ActiveDocument
if doc is not None:
- fname = doc.Label #doc.FileName
+ fname = doc.Label # doc.FileName
if len(fname) == 0:
- fname='untitled'
- tmpdir = tempfile.gettempdir() # get the current temporary directory
- tempfilepath = os.path.join(tmpdir,fname + u'-exported.step')
- sel=FreeCADGui.Selection.getSelection()
- if len (sel) == 1:
+ fname = "untitled"
+ tmpdir = tempfile.gettempdir() # get the current temporary directory
+ tempfilepath = os.path.join(tmpdir, fname + "-exported.step")
+ sel = FreeCADGui.Selection.getSelection()
+ if len(sel) == 1:
doc_obj_nbr = len(doc.Objects)
- __objs__=[]
+ __objs__ = []
__objs__.append(sel[0])
docG.getObject(sel[0].Name).Visibility = False
FreeCADGui.Selection.clearSelection()
##ReadShapeCompoundMode
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- ReadShapeCompoundMode_status=paramGetVS.GetBool("ReadShapeCompoundMode")
- #sayerr("checking ReadShapeCompoundMode")
- print("ReadShapeCompoundMode status "+str(ReadShapeCompoundMode_status))
+ ReadShapeCompoundMode_status = paramGetVS.GetBool("ReadShapeCompoundMode")
+ # sayerr("checking ReadShapeCompoundMode")
+ print("ReadShapeCompoundMode status " + str(ReadShapeCompoundMode_status))
restore_settings = False
if ReadShapeCompoundMode_status:
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- paramGetVS.SetBool("ReadShapeCompoundMode",False)
+ paramGetVS.SetBool("ReadShapeCompoundMode", False)
print("disabling ReadShapeCompoundMode")
restore_settings = True
import ImportGui
- ImportGui.export(__objs__,tempfilepath)
+
+ ImportGui.export(__objs__, tempfilepath)
del __objs__
- ImportGui.insert(tempfilepath,doc.Name)
+ ImportGui.insert(tempfilepath, doc.Name)
if restore_settings:
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- paramGetVS.SetBool("ReadShapeCompoundMode",True)
+ paramGetVS.SetBool("ReadShapeCompoundMode", True)
print("re-enabling ReadShapeCompoundMode")
doc_newobj_nbr = len(doc.Objects)
- if (doc_newobj_nbr-doc_obj_nbr) >1:
- msg='Exporting to STEP would create a multi solids object!\n'
- msg1="""Exporting to STEP would create a multi solids object!"""
- reply = QtGui.QMessageBox.warning(None,"Warning", msg1)
+ if (doc_newobj_nbr - doc_obj_nbr) > 1:
+ msg = "Exporting to STEP would create a multi solids object!\n"
+ msg1 = """Exporting to STEP would create a multi solids object!"""
+ QtGui.QMessageBox.warning(None, "Warning", msg1)
FreeCAD.Console.PrintError(msg)
else:
FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.ActiveObject)
ksuToolsCheckSolid.Activated(FreeCAD.ActiveDocument.ActiveObject)
- if '.[solid]' not in FreeCAD.ActiveDocument.ActiveObject.Label:
- msg='Exporting to STEP would create a single NON solids object!\n'
- msg1="""Exporting to STEP would create a single NON solids object!"""
- reply = QtGui.QMessageBox.warning(None,"Warning", msg1)
+ if ".[solid]" not in FreeCAD.ActiveDocument.ActiveObject.Label:
+ msg = "Exporting to STEP would create a single NON solids object!\n"
+ msg1 = """Exporting to STEP would create a single NON solids object!"""
+ QtGui.QMessageBox.warning(None, "Warning", msg1)
FreeCAD.Console.PrintError(msg)
else:
- msg='Exporting to STEP would create a single solids object!\n'
- reply = QtGui.QMessageBox.information(None,"Info", msg)
+ msg = "Exporting to STEP would create a single solids object!\n"
+ QtGui.QMessageBox.information(None, "Info", msg)
FreeCAD.Console.PrintMessage(msg)
FreeCADGui.SendMsgToActiveView("ViewFit")
- FreeCAD.Console.PrintMessage(tempfilepath+u'\n')
+ FreeCAD.Console.PrintMessage(tempfilepath + "\n")
-FreeCADGui.addCommand('checkSolidExpSTEP',checkSolidExpSTEP())
+FreeCADGui.addCommand("checkSolidExpSTEP", checkSolidExpSTEP())
-class Restore_Transparency():
+
+class Restore_Transparency:
"ksu tools Restore Transparency to Active Document Objects"
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("Restore_Transparency","Restore Transparency to Active Document Objects")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Restore_Transparency.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
+ mybtn_tooltip = QT_TRANSLATE_NOOP("Restore_Transparency", "Restore Transparency to Active Document Objects")
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Restore_Transparency.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
- def Activated(self):
+ def Activated(self):
doc = FreeCAD.ActiveDocument
if doc is None:
FreeCAD.Console.Print("No Active Document found")
return
- else:
- for obj in doc.Objects:
- if hasattr (obj, 'ViewObject'):
- if hasattr (obj.ViewObject, 'Transparency'):
- if obj.ViewObject.Transparency < 100:
- transparency = obj.ViewObject.Transparency
- obj.ViewObject.Transparency = transparency + 1
- obj.ViewObject.Transparency = transparency
+ for obj in doc.Objects:
+ if hasattr(obj, "ViewObject") and hasattr(obj.ViewObject, "Transparency"):
+ if obj.ViewObject.Transparency < 100:
+ transparency = obj.ViewObject.Transparency
+ obj.ViewObject.Transparency = transparency + 1
+ obj.ViewObject.Transparency = transparency
return
def IsActive(self):
doc = FreeCAD.activeDocument()
- if doc is None: return False
- return True
+ return doc is not None
-FreeCADGui.addCommand('Restore_Transparency',Restore_Transparency())
-class Arcs2Circles():
+FreeCADGui.addCommand("Restore_Transparency", Restore_Transparency())
+
+
+class Arcs2Circles:
"ksu tools Convert Arcs to Circles in Sketch"
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("Arcs2Circles","Convert Arcs to Circles in Sketch")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'arc2circle.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
+ mybtn_tooltip = QT_TRANSLATE_NOOP("Arcs2Circles", "Convert Arcs to Circles in Sketch")
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "arc2circle.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
- def Activated(self):
+ def Activated(self):
import kicadStepUptools
- reload_lib( kicadStepUptools )
+
+ reload_lib(kicadStepUptools)
sel = FreeCADGui.Selection.getSelection()
o = sel[0]
- centers=[];rads=[]
- for idx,g in enumerate(o.Geometry):
- if 'Circle' in str(g) and kicadStepUptools.isConstruction(g) == False:
- found=False
- for i,c in enumerate(centers):
- #if not (g.Center in centers and g.Radius in rads):
- if c == g.Center:
- if g.Radius == rads[i]:
- found=True
- continue
+ centers = []
+ rads = []
+ for idx, g in enumerate(o.Geometry):
+ if "Circle" in str(g) and not kicadStepUptools.isConstruction(g):
+ found = False
+ for i, c in enumerate(centers):
+ # if not (g.Center in centers and g.Radius in rads):
+ if c == g.Center and g.Radius == rads[i]:
+ found = True
+ continue
if not found:
- centers.append(g.Center);rads.append(g.Radius)
- #print(len(centers), centers)
- skLabel = o.Label+"_circles"
- FreeCAD.ActiveDocument.addObject('Sketcher::SketchObject', skLabel)
- skd_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.ActiveObject.Label = skLabel #workaround to keep '=' in Label
- #print(centers)
- for i,c in enumerate(centers):
- FreeCAD.ActiveDocument.getObject(skd_name).addGeometry(Part.Circle(FreeCAD.Vector(c[0], c[1]), FreeCAD.Vector(0, 0, 1), rads[i]))
- FreeCADGui.ActiveDocument.getObject(o.Name).Visibility=False
+ centers.append(g.Center)
+ rads.append(g.Radius)
+ # print(len(centers), centers)
+ skLabel = o.Label + "_circles"
+ FreeCAD.ActiveDocument.addObject("Sketcher::SketchObject", skLabel)
+ skd_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.ActiveObject.Label = skLabel # workaround to keep '=' in Label
+ # print(centers)
+ for i, c in enumerate(centers):
+ FreeCAD.ActiveDocument.getObject(skd_name).addGeometry(
+ Part.Circle(FreeCAD.Vector(c[0], c[1]), FreeCAD.Vector(0, 0, 1), rads[i]),
+ )
+ FreeCADGui.ActiveDocument.getObject(o.Name).Visibility = False
FreeCAD.ActiveDocument.recompute()
def IsActive(self):
sel = FreeCADGui.Selection.getSelection()
- if len (sel) == 1:
- if sel[0].TypeId == 'Sketcher::SketchObject':
- return True
- else:
- return False
- else:
- return False
+ if len(sel) == 1:
+ return sel[0].TypeId == "Sketcher::SketchObject"
+ return False
+
-FreeCADGui.addCommand('Arcs2Circles',Arcs2Circles())
+FreeCADGui.addCommand("Arcs2Circles", Arcs2Circles())
-class approximateCenter():
+
+class approximateCenter:
"ksu tools Create Center of Circle through 3 Vertices"
def GetResources(self):
- mybtn_tooltip =QT_TRANSLATE_NOOP("approximateCenter","Create Center of Circle through 3 Vertices or Select two vertices to create a mid point or Select a Shape to create a center point")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Three-Points-Center.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("approximateCenter","Create Center of Circle through 3 Vertices") ,
- 'ToolTip' : mybtn_tooltip}
+ mybtn_tooltip = QT_TRANSLATE_NOOP(
+ "approximateCenter",
+ "Create Center of Circle through 3 Vertices or Select two vertices to create a mid point or Select a Shape to create a center point",
+ )
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Three-Points-Center.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("approximateCenter", "Create Center of Circle through 3 Vertices"),
+ "ToolTip": mybtn_tooltip,
+ }
- def Activated(self):
+ def Activated(self):
selt = FreeCADGui.Selection.getSelectionEx()
import Draft
- import math
+
def circle_center(A, B, C):
- '''Return the circumcenter of three 3D vertices'''
- a2 = (B - C).Length**2
- b2 = (C - A).Length**2
- c2 = (A - B).Length**2
- a = (B - C).Length
- b = (C - A).Length
- c = (A - B).Length
+ """Return the circumcenter of three 3D vertices"""
+ a2 = (B - C).Length ** 2
+ b2 = (C - A).Length ** 2
+ c2 = (A - B).Length ** 2
+ a = (B - C).Length
+ b = (C - A).Length
+ c = (A - B).Length
if a2 * b2 * c2 == 0.0:
- print('Three vertices must be distinct')
- return
+ print("Three vertices must be distinct")
+ return None
alpha = a2 * (b2 + c2 - a2)
beta = b2 * (c2 + a2 - b2)
gamma = c2 * (a2 + b2 - c2)
s = (a + b + c) / 2
- radius = a*b*c / 4 / math.sqrt(s * (s - a) * (s - b) * (s - c))
- return (alpha*A + beta * B + gamma * C)/(alpha + beta + gamma) , radius
-
+ radius = a * b * c / 4 / math.sqrt(s * (s - a) * (s - b) * (s - c))
+ return (alpha * A + beta * B + gamma * C) / (alpha + beta + gamma), radius
+
if len(selt) != 1:
- #print('Len='+str(len(selt))+' Select three vertices to create a point in the center of approximate circle')
- print('Select three vertices to create a point in the center of approximate circle')
- print('Select two vertices to create a mid point')
- print('Select a Shape to create a center point')
+ # print('Len='+str(len(selt))+' Select three vertices to create a point in the center of approximate circle')
+ print("Select three vertices to create a point in the center of approximate circle")
+ print("Select two vertices to create a mid point")
+ print("Select a Shape to create a center point")
else:
to_process = False
to_process_center = False
- debug=False
+ debug = False
sel = selt[0]
if sel.HasSubObjects:
vv = sel.SubObjects
- if len(vv) ==3 and vv[0].ShapeType == 'Vertex' and vv[1].ShapeType == 'Vertex' and vv[2].ShapeType == 'Vertex':
+ if (
+ len(vv) == 3
+ and vv[0].ShapeType == "Vertex"
+ and vv[1].ShapeType == "Vertex"
+ and vv[2].ShapeType == "Vertex"
+ ):
shift, rd = circle_center(vv[0].Point, vv[1].Point, vv[2].Point)
- suffix = '_center'
+ suffix = "_center"
to_process = True
to_process_center = True
- print (rd)
- #print(shift)
- elif len(vv) ==2 and vv[0].ShapeType == 'Vertex' and vv[1].ShapeType == 'Vertex':
- halfedge = (vv[0].Point.sub(vv[1].Point)).multiply(.5)
- mid=FreeCAD.Vector.add(vv[1].Point,halfedge)
+ print(rd)
+ # print(shift)
+ elif len(vv) == 2 and vv[0].ShapeType == "Vertex" and vv[1].ShapeType == "Vertex":
+ halfedge = (vv[0].Point.sub(vv[1].Point)).multiply(0.5)
+ mid = FreeCAD.Vector.add(vv[1].Point, halfedge)
shift = mid
- suffix = '_mid'
+ suffix = "_mid"
# print (shift)
to_process = True
- elif hasattr(sel.Object, 'Shape'):
+ elif hasattr(sel.Object, "Shape"):
shape = sel.Object.Shape
- if shape.ShapeType == 'Solid' or shape.ShapeType == 'Shell':
+ if shape.ShapeType in {"Solid", "Shell"}:
shift = shape.CenterOfMass
- suffix = '_com'
+ suffix = "_com"
to_process = True
- elif shape.ShapeType == 'Compound' or shape.ShapeType == 'CompSolid':
- print('Centering on Bounding Box of Compound '+sel.Object.Label)
+ elif shape.ShapeType in {"Compound", "CompSolid"}:
+ print("Centering on Bounding Box of Compound " + sel.Object.Label)
bb = shape.BoundBox
- shift = FreeCAD.Vector(bb.XLength/2+bb.XMin,bb.YLength/2+bb.YMin,bb.ZLength/2+bb.ZMin)
- suffix = '_bbc'
+ shift = FreeCAD.Vector(bb.XLength / 2 + bb.XMin, bb.YLength / 2 + bb.YMin, bb.ZLength / 2 + bb.ZMin)
+ suffix = "_bbc"
to_process = True
if to_process:
- FreeCAD.ActiveDocument.openTransaction('Undo Create Center')
- nPt=Draft.makePoint(shift)
- nPt.Label = sel.Object.Label+suffix
+ FreeCAD.ActiveDocument.openTransaction("Undo Create Center")
+ nPt = Draft.makePoint(shift)
+ nPt.Label = sel.Object.Label + suffix
npt_Pl = nPt.Placement
- FreeCADGui.ActiveDocument.getObject(nPt.Name).PointColor = (0.333,0.667,1.000) #(1.000,0.667,0.498)
+ FreeCADGui.ActiveDocument.getObject(nPt.Name).PointColor = (0.333, 0.667, 1.000) # (1.000,0.667,0.498)
FreeCADGui.ActiveDocument.getObject(nPt.Name).PointSize = 10.000
if to_process_center:
circle = Draft.makeCircle(radius=rd, placement=npt_Pl, face=False, support=None)
- circle.Label = sel.Object.Label+'_circle'
- FreeCADGui.ActiveDocument.getObject(circle.Name).LineColor = (0.333,0.667,1.000)
+ circle.Label = sel.Object.Label + "_circle"
+ FreeCADGui.ActiveDocument.getObject(circle.Name).LineColor = (0.333, 0.667, 1.000)
if len(sel.Object.InList) == 0:
- FreeCAD.ActiveDocument.addObject('App::Part',sel.Object.Label+'_Part')
+ FreeCAD.ActiveDocument.addObject("App::Part", sel.Object.Label + "_Part")
nP = FreeCAD.ActiveDocument.ActiveObject.Parents[0][0]
else:
nP = sel.Object.InList[0]
if debug:
- print(nP.Label);print(nP.Name);print(nPt.Label);print(nPt.Name)
- if len (sel.Object.InList) >= 1:
+ print(nP.Label)
+ print(nP.Name)
+ print(nPt.Label)
+ print(nPt.Name)
+ if len(sel.Object.InList) >= 1:
print(sel.Object.InList[0].Label)
- #FreeCAD.ActiveDocument.getObject(nPt.Name).adjustRelativeLinks(FreeCAD.ActiveDocument.getObject(nP.Name))
+ # FreeCAD.ActiveDocument.getObject(nPt.Name).adjustRelativeLinks(FreeCAD.ActiveDocument.getObject(nP.Name))
FreeCAD.ActiveDocument.getObject(nP.Name).addObject(FreeCAD.ActiveDocument.getObject(nPt.Name))
if to_process_center:
FreeCAD.ActiveDocument.getObject(nP.Name).addObject(FreeCAD.ActiveDocument.getObject(circle.Name))
@@ -4985,34 +5729,37 @@ def circle_center(A, B, C):
def IsActive(self):
selt = FreeCADGui.Selection.getSelectionEx()
- if len(selt) < 1:
- return False
- else:
- return True
+ return not len(selt) < 1
+
+
+FreeCADGui.addCommand("approximateCenter", approximateCenter())
-FreeCADGui.addCommand('approximateCenter',approximateCenter())
-class Create_BoundBox():
+class Create_BoundBox:
"Create BoundBox of the Selected Object"
def GetResources(self):
mybtn_tooltip = QT_TRANSLATE_NOOP("Create_BoundBox", "Create BoundBox of the Selected Object")
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'BoundBox.svg') , # the name of a svg file available in the resources
- 'MenuText': mybtn_tooltip ,
- 'ToolTip' : mybtn_tooltip}
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "BoundBox.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": mybtn_tooltip,
+ "ToolTip": mybtn_tooltip,
+ }
def IsActive(self):
doc = FreeCAD.ActiveDocument
- if doc is not None:
- if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- if len(sel)>=1:
- return True
- return
+ if doc is not None and FreeCADGui.Selection.getSelection():
+ sel = FreeCADGui.Selection.getSelection()
+ if len(sel) >= 1:
+ return True
+ return None
- def Activated(self):
- def make_shape_from_mesh (d,m):
- d.addObject('Part::Feature', 'Shape-Mesh')
+ def Activated(self):
+ def make_shape_from_mesh(d, m):
+ d.addObject("Part::Feature", "Shape-Mesh")
sm = d.ActiveObject
__shape__ = Part.Shape()
__shape__.makeShapeFromMesh(m.Mesh.Topology, 0.100000, False)
@@ -5022,227 +5769,258 @@ def make_shape_from_mesh (d,m):
return sm
import Part
+
doc = FreeCAD.ActiveDocument
if FreeCADGui.Selection.getSelection():
- sel=FreeCADGui.Selection.getSelection()
- if len(sel)==1:
+ sel = FreeCADGui.Selection.getSelection()
+ if len(sel) == 1:
selObj = sel[0]
- bbLbl = selObj.Label+"-BBox"
+ bbLbl = selObj.Label + "-BBox"
bb = None
- if hasattr(selObj, 'Shape'):
- combined_path = '\t'.join(sys.path)
- if 'Assembly4' in combined_path:
+ if hasattr(selObj, "Shape"):
+ combined_path = "\t".join(sys.path)
+ if "Assembly4" in combined_path:
import showHideLcsCmd
+
showHideLcsCmd.showHide(0)
- FreeCAD.Console.PrintMessage('hiding LCs\n')
- #FreeCADGui.runCommand('Asm4_hideLcs',0)
+ FreeCAD.Console.PrintMessage("hiding LCs\n")
+ # FreeCADGui.runCommand('Asm4_hideLcs',0)
else:
for e in selObj.OutList:
- if e.TypeId == 'PartDesign::CoordinateSystem':
- FreeCAD.Console.PrintMessage('hiding LCs\n')
+ if e.TypeId == "PartDesign::CoordinateSystem":
+ FreeCAD.Console.PrintMessage("hiding LCs\n")
e.ViewObject.Visibility = False
bb = selObj.Shape.BoundBox
- elif hasattr(selObj, 'Mesh'):
+ elif hasattr(selObj, "Mesh"):
bb = selObj.ViewObject.getBoundingBox()
if bb is not None:
- if len(FreeCAD.ActiveDocument.getObjectsByLabel(bbLbl))==0:
- FreeCAD.ActiveDocument.addObject("Part::Box","Box")
+ if len(FreeCAD.ActiveDocument.getObjectsByLabel(bbLbl)) == 0:
+ FreeCAD.ActiveDocument.addObject("Part::Box", "Box")
bbO = FreeCAD.ActiveDocument.ActiveObject
else:
bbO = FreeCAD.ActiveDocument.getObjectsByLabel(bbLbl)[0]
bbO.Label = bbLbl
# selObj.Label+"-BB"
- bbO.ViewObject.Transparency=90
- bbO.ViewObject.Visibility=True
+ bbO.ViewObject.Transparency = 90
+ bbO.ViewObject.Visibility = True
# bbO.ViewObject.ShapeColor = (0.67,0.00,0.00) # (0.00,0.00,0.50)
- sel_Old = sel[0]
+ sel[0]
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(bbO)
- FreeCADGui.runCommand('Std_RandomColor')
+ FreeCADGui.runCommand("Std_RandomColor")
# FreeCADGui.Selection.clearSelection()
# FreeCADGui.Selection.addSelection(selObj)
-
+
bbO.Placement.Base.x = bb.XMin
bbO.Placement.Base.y = bb.YMin
bbO.Placement.Base.z = bb.ZMin
if bb.XLength > 0:
- bbO.Length=bb.XLength
+ bbO.Length = bb.XLength
else:
- bbO.Length=0.01
+ bbO.Length = 0.01
if bb.YLength > 0:
- bbO.Width=bb.YLength
+ bbO.Width = bb.YLength
else:
- bbO.Width=0.01
+ bbO.Width = 0.01
if bb.ZLength > 0:
- bbO.Height=bb.ZLength
+ bbO.Height = bb.ZLength
else:
- bbO.Height=0.01
- FreeCAD.Console.PrintMessage('BB data x:'+str(bb.XLength)+", y:"+str(bb.YLength)+", z:"+str(bb.ZLength)+'\n')
+ bbO.Height = 0.01
+ FreeCAD.Console.PrintMessage(
+ "BB data x:" + str(bb.XLength) + ", y:" + str(bb.YLength) + ", z:" + str(bb.ZLength) + "\n",
+ )
FreeCAD.ActiveDocument.recompute()
FreeCADGui.SendMsgToActiveView("ViewFit")
else:
- doc.addObject("Part::Compound","BBox-Compound")
- BBCompound= doc.ActiveObject
- sel_Old = sel
+ doc.addObject("Part::Compound", "BBox-Compound")
+ BBCompound = doc.ActiveObject
cmpd_objs = []
toDel_objs = []
for o in sel:
- if hasattr(o.ViewObject, 'Visibility'):
- if o.ViewObject.Visibility==True:
- if hasattr(o, 'Shape'):
- combined_path = '\t'.join(sys.path)
- if 'Assembly4' in combined_path:
- import showHideLcsCmd
- showHideLcsCmd.showHide(0)
- FreeCAD.Console.PrintMessage('hiding LCs\n')
- #FreeCADGui.runCommand('Asm4_hideLcs',0)
- else:
- for e in o.OutList:
- if e.TypeId == 'PartDesign::CoordinateSystem':
- FreeCAD.Console.PrintMessage('hiding LCs\n')
- e.ViewObject.Visibility = False
- cmpd_objs.append(o)
- elif hasattr(o, 'Mesh'):
- sm = make_shape_from_mesh (doc,o)
- cmpd_objs.append(sm)
- toDel_objs.append(sm)
- BBCompound.Links = cmpd_objs # sel
+ if hasattr(o.ViewObject, "Visibility") and o.ViewObject.Visibility:
+ if hasattr(o, "Shape"):
+ combined_path = "\t".join(sys.path)
+ if "Assembly4" in combined_path:
+ import showHideLcsCmd
+
+ showHideLcsCmd.showHide(0)
+ FreeCAD.Console.PrintMessage("hiding LCs\n")
+ # FreeCADGui.runCommand('Asm4_hideLcs',0)
+ else:
+ for e in o.OutList:
+ if e.TypeId == "PartDesign::CoordinateSystem":
+ FreeCAD.Console.PrintMessage("hiding LCs\n")
+ e.ViewObject.Visibility = False
+ cmpd_objs.append(o)
+ elif hasattr(o, "Mesh"):
+ sm = make_shape_from_mesh(doc, o)
+ cmpd_objs.append(sm)
+ toDel_objs.append(sm)
+ BBCompound.Links = cmpd_objs # sel
doc.recompute()
bb = BBCompound.Shape.BoundBox
- doc.addObject("Part::Box","Box")
+ doc.addObject("Part::Box", "Box")
bbO = doc.ActiveObject
bbO.Label = "BBox-multiObjects"
- bbO.ViewObject.Transparency=90
- bbO.ViewObject.Visibility=True
+ bbO.ViewObject.Transparency = 90
+ bbO.ViewObject.Visibility = True
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(bbO)
- FreeCADGui.runCommand('Std_RandomColor')
+ FreeCADGui.runCommand("Std_RandomColor")
bbO.ViewObject.LineColor = bbO.ViewObject.ShapeColor
bbO.Placement.Base.x = bb.XMin
bbO.Placement.Base.y = bb.YMin
bbO.Placement.Base.z = bb.ZMin
if bb.XLength > 0:
- bbO.Length=bb.XLength
+ bbO.Length = bb.XLength
else:
- bbO.Length=0.01
+ bbO.Length = 0.01
if bb.YLength > 0:
- bbO.Width=bb.YLength
+ bbO.Width = bb.YLength
else:
- bbO.Width=0.01
+ bbO.Width = 0.01
if bb.ZLength > 0:
- bbO.Height=bb.ZLength
+ bbO.Height = bb.ZLength
else:
- bbO.Height=0.01
- FreeCAD.Console.PrintMessage('BB data x:'+str(bb.XLength)+", y:"+str(bb.YLength)+", z:"+str(bb.ZLength)+'\n')
+ bbO.Height = 0.01
+ FreeCAD.Console.PrintMessage(
+ "BB data x:" + str(bb.XLength) + ", y:" + str(bb.YLength) + ", z:" + str(bb.ZLength) + "\n",
+ )
doc.recompute()
for o in cmpd_objs:
- o.ViewObject.Visibility=True
+ o.ViewObject.Visibility = True
FreeCADGui.SendMsgToActiveView("ViewFit")
doc.removeObject(BBCompound.Name)
for o in toDel_objs:
doc.removeObject(o.Name)
doc.recompute()
-
-FreeCADGui.addCommand('Create_BoundBox',Create_BoundBox())
+
+
+FreeCADGui.addCommand("Create_BoundBox", Create_BoundBox())
+
#####
class ksuToolsImportFootprint:
"ksu tools Load Footprint object"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'importFPs.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsImportFootprint", "Load FootPrint"),
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsImportFootprint", "ksu Load KiCad PCB FootPrint")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "importFPs.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsImportFootprint", "Load FootPrint"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsImportFootprint", "ksu Load KiCad PCB FootPrint"),
+ }
+
def IsActive(self):
- #if FreeCAD.ActiveDocument == None:
+ # if FreeCAD.ActiveDocument == None:
# return False
- #else:
+ # else:
# return True
- #import kicadStepUptools
+ # import kicadStepUptools
return True
-
+
def Activated(self):
# do something here...
import kicadStepUptools
- #if not kicadStepUptools.checkInstance():
+
+ # if not kicadStepUptools.checkInstance():
# reload( kicadStepUptools )
- if 1: #reload_Gui:
- reload_lib( kicadStepUptools )
- #FreeCAD.Console.PrintWarning( 'active :)\n' )
+ if 1: # reload_Gui:
+ reload_lib(kicadStepUptools)
+ # FreeCAD.Console.PrintWarning( 'active :)\n' )
if 0:
kicadStepUptools.KSUWidget.activateWindow()
kicadStepUptools.KSUWidget.show()
kicadStepUptools.KSUWidget.raise_()
kicadStepUptools.onLoadFootprint()
import fps
- reload_lib( fps )
- doc = FreeCAD.ActiveDocument
+
+ reload_lib(fps)
fps.addfootprint()
-
-FreeCADGui.addCommand('ksuToolsImportFootprint',ksuToolsImportFootprint())
+
+
+FreeCADGui.addCommand("ksuToolsImportFootprint", ksuToolsImportFootprint())
+
+
##
class ksuToolsSelection2Edges:
"ksu tools Selection 2 Edges"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'Select_edges.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsSelection2Edges","Selection 2 Edges") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsSelection2Edges","ksu Selection 2 Edges")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "Select_edges.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsSelection2Edges", "Selection 2 Edges"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsSelection2Edges", "ksu Selection 2 Edges"),
+ }
+
def IsActive(self):
- selEx=FreeCADGui.Selection.getSelectionEx()
- if len (selEx) > 0:
+ selEx = FreeCADGui.Selection.getSelectionEx()
+ if len(selEx) > 0:
return True
-
+ return None
+
def Activated(self):
# do something here...
- selEx=FreeCADGui.Selection.getSelectionEx()
- if len (selEx) > 0:
+ selEx = FreeCADGui.Selection.getSelectionEx()
+ if len(selEx) > 0:
# print('here')
import selection2edges
+
selection2edges.sel2edges()
-
+
else:
- #FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
- reply = QtGui.QMessageBox.information(None,"Warning", "Select one or more edge(s) to create a sketch!")
- FreeCAD.Console.PrintWarning("Select one or more edge(s) to create a sketch!\n")
+ # FreeCAD.Console.PrintError("Select elements from dxf imported file\n")
+ QtGui.QMessageBox.information(None, "Warning", "Select one or more edge(s) to create a sketch!")
+ FreeCAD.Console.PrintWarning("Select one or more edge(s) to create a sketch!\n")
-FreeCADGui.addCommand('ksuToolsSelection2Edges',ksuToolsSelection2Edges())
+
+FreeCADGui.addCommand("ksuToolsSelection2Edges", ksuToolsSelection2Edges())
#####
class ksuToolsAlignView:
"ksu tools AlignView to Face"
-
+
def GetResources(self):
- return {'Pixmap' : os.path.join( ksuWB_icons_path , 'AlignView2Face.svg') , # the name of a svg file available in the resources
- 'MenuText': QT_TRANSLATE_NOOP("ksuToolsAlignView", "AlignView to Face") ,
- 'ToolTip' : QT_TRANSLATE_NOOP("ksuToolsAlignView", "ksu AlignView to Face")}
-
+ return {
+ "Pixmap": os.path.join(
+ ksuWB_icons_path,
+ "AlignView2Face.svg",
+ ), # the name of a svg file available in the resources
+ "MenuText": QT_TRANSLATE_NOOP("ksuToolsAlignView", "AlignView to Face"),
+ "ToolTip": QT_TRANSLATE_NOOP("ksuToolsAlignView", "ksu AlignView to Face"),
+ }
+
def IsActive(self):
doc = FreeCAD.ActiveDocument
- if doc is not None:
- if FreeCADGui.Selection.getSelectionEx():
- sl=FreeCADGui.Selection.getSelectionEx()
- if len (sl[0].SubObjects)==1:
- if 'Vertex' not in str(sl[0].SubObjects[0]) and 'Edge' not in str(sl[0].SubObjects[0]):
- return True
- return
-
+ if doc is not None and FreeCADGui.Selection.getSelectionEx():
+ sl = FreeCADGui.Selection.getSelectionEx()
+ if len(sl[0].SubObjects) == 1:
+ if "Vertex" not in str(sl[0].SubObjects[0]) and "Edge" not in str(sl[0].SubObjects[0]):
+ return True
+ return None
+
def Activated(self):
# do something here...
AlignView2Face()
-
-FreeCADGui.addCommand('ksuToolsAlignView',ksuToolsAlignView())
+
+
+FreeCADGui.addCommand("ksuToolsAlignView", ksuToolsAlignView())
+
+
##
def AlignView2Face():
- """ macro Macro_Align_View_to_Face
- App:Part and Body compliant"""
-
- inv_view=False
-
+ """macro Macro_Align_View_to_Face
+ App:Part and Body compliant"""
+
+ inv_view = False
+
def pointAt(normal, up):
z = normal
y = up
@@ -5260,38 +6038,37 @@ def pointAt(normal, up):
rot.A33 = z.z
return FreeCAD.Placement(rot).Rotation
- #try:
- sl=FreeCADGui.Selection.getSelectionEx()
- if len (sl)>0:
- if len (sl[0].SubObjects)>0:
- if 'Vertex' not in str(sl[0].SubObjects[0]) and 'Edge' not in str(sl[0].SubObjects[0]):
- # QtCore.QTimer.singleShot(doubleClickDly,onDoubleClick)
- ob=sl[0]
- #faceSel = ob.SubObjects[0]
- norm, plcm, top, bbC = getNormalPlacementHierarchy (sl[0])
- cam = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
+ # try:
+ sl = FreeCADGui.Selection.getSelectionEx()
+ if len(sl) > 0 and len(sl[0].SubObjects) > 0:
+ if "Vertex" not in str(sl[0].SubObjects[0]) and "Edge" not in str(sl[0].SubObjects[0]):
+ # QtCore.QTimer.singleShot(doubleClickDly,onDoubleClick)
+ sl[0]
+ # faceSel = ob.SubObjects[0]
+ norm, _plcm, _top, _bbC = getNormalPlacementHierarchy(sl[0])
+ cam = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
+
+ if inv_view: #:
+ # sayerr('double click: inversion View')
+ # dirz = faceSel.normalAt(0,0)*-1
+ dirz = norm * -1
+ else:
+ # sayw('single click: standard View')
+ # dirz = faceSel.normalAt(0,0)
+ dirz = norm
+ if dirz.z in (1, -1):
+ rot = pointAt(dirz, FreeCAD.Vector(0.0, 1.0, 0.0))
+ else:
+ rot = pointAt(dirz, FreeCAD.Vector(0.0, 0.0, -1.0))
+
+ cam.orientation.setValue(rot.Q)
+ # FreeCADGui.SendMsgToActiveView("ViewSelection")
+ FreeCADGui.SendMsgToActiveView("ViewFit")
+ inv_view = True
+ for s in FreeCADGui.Selection.getSelection():
+ FreeCADGui.Selection.removeSelection(s)
+
- if inv_view==True: #:
- # sayerr('double click: inversion View')
- #dirz = faceSel.normalAt(0,0)*-1
- dirz = norm*-1
- else:
- # sayw('single click: standard View')
- #dirz = faceSel.normalAt(0,0)
- dirz = norm
- if dirz.z == 1 :
- rot = pointAt(dirz, FreeCAD.Vector(0.0,1.0,0.0))
- elif dirz.z == -1 :
- rot = pointAt(dirz, FreeCAD.Vector(0.0,1.0,0.0))
- else :
- rot = pointAt(dirz, FreeCAD.Vector(0.0,0.0,-1.0))
-
- cam.orientation.setValue(rot.Q)
- #FreeCADGui.SendMsgToActiveView("ViewSelection")
- FreeCADGui.SendMsgToActiveView("ViewFit")
- inv_view = True
- for s in FreeCADGui.Selection.getSelection():
- FreeCADGui.Selection.removeSelection(s)
##
diff --git a/kicadStepUptools.py b/kicadStepUptools.py
index 34516db..2d59f6d 100644
--- a/kicadStepUptools.py
+++ b/kicadStepUptools.py
@@ -1,73 +1,72 @@
#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#****************************************************************************
-#* *
-#* Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
-#* 3D exporter for FreeCAD *
-#* Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
-#* Copyright (c) 2015 *
-#* Maurice easyw@katamail.com *
-#* *
-#* Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
-#* *
-#* code partially based on: *
-#* Printed Circuit Board Workbench for FreeCAD FreeCAD-PCB *
-#* Copyright (c) 2013, 2014, 2015 *
-#* marmni *
-#* *
-#* and IDF import for FreeCAD *
-#* (c) Milos Koutny (milos.koutny@gmail.com) 2012 *
-#* and (c) hyOzd ecad-3d-model-generator *
-#* *
-#* this macro rotates, translates and scales one object *
-#* scale for VRML export and open footprint for easy alignment *
-#* this sw is a part of kicad StepUp code *
-#* all credits and licence details in kicad StepUp code *
-#* Macro_Move_Rotate_Scale *
-#* ver in ___ver___ *
-#* Copyright (c) 2015, 2016, 2017 *
-#* Maurice easyw@katamail.com *
-#* *
-#* Collisions routines from Highlight Common parts Macro *
-#* author JMG, galou and other contributors *
-#* from FreeCAD OpenSCAD Workbench - 2D helper functions *
-#* __author__ = "Sebastian Hoogen" *
-#* *
-#* semantic parser from __author__ = "Zheng, Lei" fcad_pcb *
-#* *
-#* IDF_ImporterVersion="3.9.2"
-#* ignoring step search associations (too old models)
-#* displaying Flat Mode models
-#* checking version 3 for both Geometry and Part Number
-#* supporting Z position
-#* skipping PROP in emp file
-#* adding color to shapes opt IDF_colorize
-#* adding emp library/single model load support
-#* aligning IDF shape to both Geom and PartNBR for exactly match
-#* to do: .ROUTE_OUTLINE ECAD, .PLACE_OUTLINE MCAD, .ROUTE_KEPOUT ECAD, .PLACE_KEEPOUT ECAD
-#****************************************************************************
-#* *
-#* This program is free software; you can redistribute it and/or modify *
-#* it under the terms of the GNU Affero General Public License *
-#* as published by the Free Software Foundation to ensure cooperation *
-#* with the community in the case of network server software; *
-#* for detail see the LICENCE text file. *
-#* http://www.gnu.org/licenses/agpl-3.0.en.html *
-#* Moreover you have to include the original author copyright *
-#* kicad StepUP made by Maurice easyw@katamail.com *
-#* *
-#* This program is distributed in the hope that it will be useful, *
-#* but WITHOUT ANY WARRANTY; without even the implied warranty of *
-#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
-#* GNU Library General Public License for more details. *
-#* *
-#* You should have received a copy of the GNU Library General Public *
-#* License along with this program; if not, write to the Free Software *
-#* Foundation, Inc., *
-#* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *
-#* *
-#****************************************************************************
-##With kicad StepUp you’ll get an exact representation of your physical board in Native 3D PCB
+# ****************************************************************************
+# * *
+# * Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
+# * 3D exporter for FreeCAD *
+# * Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
+# * Copyright (c) 2015 *
+# * Maurice easyw@katamail.com *
+# * *
+# * Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
+# * *
+# * code partially based on: *
+# * Printed Circuit Board Workbench for FreeCAD FreeCAD-PCB *
+# * Copyright (c) 2013, 2014, 2015 *
+# * marmni *
+# * *
+# * and IDF import for FreeCAD *
+# * (c) Milos Koutny (milos.koutny@gmail.com) 2012 *
+# * and (c) hyOzd ecad-3d-model-generator *
+# * *
+# * this macro rotates, translates and scales one object *
+# * scale for VRML export and open footprint for easy alignment *
+# * this sw is a part of kicad StepUp code *
+# * all credits and licence details in kicad StepUp code *
+# * Macro_Move_Rotate_Scale *
+# * ver in ___ver___ *
+# * Copyright (c) 2015, 2016, 2017 *
+# * Maurice easyw@katamail.com *
+# * *
+# * Collisions routines from Highlight Common parts Macro *
+# * author JMG, galou and other contributors *
+# * from FreeCAD OpenSCAD Workbench - 2D helper functions *
+# * __author__ = "Sebastian Hoogen" *
+# * *
+# * semantic parser from __author__ = "Zheng, Lei" fcad_pcb *
+# * *
+# * IDF_ImporterVersion="3.9.2"
+# * ignoring step search associations (too old models)
+# * displaying Flat Mode models
+# * checking version 3 for both Geometry and Part Number
+# * supporting Z position
+# * skipping PROP in emp file
+# * adding color to shapes opt IDF_colorize
+# * adding emp library/single model load support
+# * aligning IDF shape to both Geom and PartNBR for exactly match
+# * to do: .ROUTE_OUTLINE ECAD, .PLACE_OUTLINE MCAD, .ROUTE_KEPOUT ECAD, .PLACE_KEEPOUT ECAD
+# ****************************************************************************
+# * *
+# * This program is free software; you can redistribute it and/or modify *
+# * it under the terms of the GNU Affero General Public License *
+# * as published by the Free Software Foundation to ensure cooperation *
+# * with the community in the case of network server software; *
+# * for detail see the LICENCE text file. *
+# * http://www.gnu.org/licenses/agpl-3.0.en.html *
+# * Moreover you have to include the original author copyright *
+# * kicad StepUP made by Maurice easyw@katamail.com *
+# * *
+# * This program is distributed in the hope that it will be useful, *
+# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+# * GNU Library General Public License for more details. *
+# * *
+# * You should have received a copy of the GNU Library General Public *
+# * License along with this program; if not, write to the Free Software *
+# * Foundation, Inc., *
+# * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *
+# * *
+# ****************************************************************************
+##With kicad StepUp you'll get an exact representation of your physical board in Native 3D PCB
## kicad StepUp tools
##done
@@ -80,7 +79,7 @@
# better arc and line import
# remove test button
# enable confirm on exit
-# replace FreeCAD.Console.Message -> say
+# replace FreeCAD.Console.Message -> say
##todo list
# collision and proximity as microelly
## kicad StepUp
@@ -115,7 +114,7 @@
# cutting hole by hole instead of hole compound
# added holes_solid var
# to have holes as solid to guarantee cutting
-# handled single circle
+# handled single circle
# used OpenSCAD2Dgeom instead of wire + face (best option)
# http://www.freecadweb.org/wiki/index.php?title=Macro_Creating_faces_from_a_DXF_file
# fixed unicode text parsing
@@ -125,7 +124,7 @@
# try to optimize cutting changing creation/type of holes
# manage bklist and volume
# accept with or without /\ at the end of 3Dpath
-# search models in KIPRJMOD and in KISYS3DMOD
+# search models in KIPRJMOD and in KISYS3DMOD
# removed unicode chars in .kicad_pcb
# exported wrl, step from python
# reload & display ini cfg file
@@ -160,7 +159,7 @@
# implemented caching for 3D models
# optimized for fusion w/ colors
# added support for alias i.e. :Kicad3D: as for environment variables
-# added crease angle for wrl export
+# added crease angle for wrl export
# added support for ${KISYS3DMOD}/ in new 3d viewer path resolver
# accepting .wrl .step .stp .iges .igs as 3d models directly in kicad_pcb
# added fixedPosition for aligning part to footprint in assembly2
@@ -280,16 +279,16 @@
# improve help and add sketch functionality
# auto constraint coincident points and vertical/horizontal
# edge_width from kicad_pcb
-# managed not supported geometry BSplines & Ellipses with optimized deviation # loop in App.ActiveDocument.PCB_Sketch.Geometry searching for coincident vertex
-# aligned Sketch to center of A4 in pcbnew if first time
+# managed not supported geometry BSplines & Ellipses with optimized deviation # loop in App.ActiveDocument.PCB_Sketch.Geometry searching for coincident vertex
+# aligned Sketch to center of A4 in pcbnew if first time
# removing sketches from export 3d to step button
# removing sketches in FC0.16 and when exporting automatically
# added use grid_origin as reference point for placing the board and for sketch!!!
- # this will allow to copy sketches between boards releases to keep constraints
+# this will allow to copy sketches between boards releases to keep constraints
# managed write permissions error message
# fixed App::Part list inverted after FC 12090 https://github.com/FreeCAD/FreeCAD/pull/916
# fixed case of pcb with one drill only
-# minor fix when exporting wrl from multi objects
+# minor fix when exporting wrl from multi objects
# fixed tabify
# added better support for Body (hidden Parts)
# fixed a regression in Sketch
@@ -333,7 +332,7 @@
# assigned combobox to defined colors
# improved generation of complex footprint with arcs
# partially implemented Circle Geometry primitive
-# improved writing fp data
+# improved writing fp data
# push Moved 3D model(s) to kicad PCB
# sync Reference in case of lost correct Label (import export STEP file with Links)
# improved precision on board data using "{:.3f}".format for pushpcb & Pushfootprint and angles
@@ -382,7 +381,7 @@
## remove print say etc, remove shape show, remove extra import, remove extra functions FC_016
## App -> FreeCAD
-# done: allow bspline on fp generator
+# done: allow bspline on fp generator
# done: completing py3 compatibility
## started to implement isInside using bboxes to check if drills are nested, and then
@@ -390,7 +389,7 @@
## or use a python feature as in pcb for having the board updated live
## approximate arcs from segments https://www.freecadweb.org/wiki/Macro_EdgesToArc
-## add AP214-203 settings read,set,restore both on step-step(h)
+## add AP214-203 settings read,set,restore both on step-step(h)
## when exporting step and step+wrl
## ... there is a mess in Tool variables after jm pr910
## use float in all data from semantic parser !!!!!
@@ -398,7 +397,7 @@
## evaluate to add comment line and behavior for font_size = 0 for default size
## evaluate makeCompound as comment line and option beside fuseAll (not useful)
-## check basepoint
+## check basepoint
## simplify pdf manual and update internal help
## assign shininess and specular color for faces? available?
## adding top bottom lights
@@ -423,91 +422,81 @@
## import statements
-import FreeCAD,FreeCADGui,Part,Mesh
-#import PySide
+# import PySide
from collections import namedtuple
+import FreeCAD
+import FreeCADGui
+import Mesh
+import Part
import PySide
-from PySide import QtGui, QtCore
+from PySide import QtCore, QtGui
+
from TranslateUtils import translate
-QtWidgets = QtGui
-from time import sleep
-from math import sqrt, tan, atan, atan2, degrees, radians, hypot, sin, cos, pi, fmod
-import Draft, Part, DraftVecUtils
-#from Draft import *
-from FreeCAD import Vector
-import Sketcher
+QtWidgets = QtGui
-from collections import namedtuple
-from FreeCAD import Base
-import sys, os
-from os.path import expanduser
-import shutil
-from shutil import copyfile
-import tempfile, errno
+import os
import re
+import sys
+import tempfile
import time
+from math import atan, atan2, cos, degrees, fmod, hypot, pi, radians, sin, sqrt
+from os.path import expanduser
+from shutil import copyfile
+import Draft
+import DraftVecUtils
+import Sketcher
-max_recursion_limit=5000 # kSU issue#198
-sys.setrecursionlimit(max_recursion_limit)
+# from Draft import *
+from FreeCAD import Base, Vector
-import ksu_locator
+max_recursion_limit = 5000 # kSU issue#198
+sys.setrecursionlimit(max_recursion_limit)
-if (sys.version_info > (3, 0)): #py3
- import builtins as builtin #py3
- import gzip as gz
-else: #py2
- import __builtin__ as builtin #py2
- try:
- import gzip_utf8 as gz
- except:
- FreeCAD.Console.PrintError("'.stpZ' not supported")
- pass
+import builtins as builtin # py3
+import gzip as gz
-import zipfile as zf
# sys.path.append('C:\Cad\Progetti_K\3D-FreeCad-tools/')
-#sys.path.append(os.path.realpath(__file__)) #workaround to test OpenSCAD2DgeomMau
-#import OpenSCAD2DgeomMau #
-#reload(OpenSCAD2DgeomMau)
-#import OpenSCAD2Dgeom
+# sys.path.append(os.path.realpath(__file__)) #workaround to test OpenSCAD2DgeomMau
+# import OpenSCAD2DgeomMau #
+# reload(OpenSCAD2DgeomMau)
+# import OpenSCAD2Dgeom
+from threading import Timer
+
import ImportGui
-from math import sqrt, atan, sin, cos, radians, degrees, pi
-import argparse
-from threading import Timer
+import ksu_locator
-#try:
+# try:
# import __builtin__ as builtin #py2
-#except:
+# except:
# import builtins as builtin #py3
if FreeCAD.GuiUp:
from PySide import QtCore, QtGui
# import OpenSCADFeatures
+import codecs # utf-8 config parser
+
+# import configparser #utf-8
+# from codecs import open #maui to verify
import DraftGeomUtils
-#from DraftGeomUtils import *
+# from DraftGeomUtils import *
from pivy.coin import SoDirectionalLight
-import codecs #utf-8 config parser
-import io
-#import configparser #utf-8
-#from codecs import open #maui to verify
-import unicodedata
-
-pythonopen = builtin.open # to distinguish python built-in open function from the one declared here
+pythonopen = builtin.open # to distinguish python built-in open function from the one declared here
## Constant definitions
___ver___ = "12.7.3"
__title__ = "kicad_StepUp"
__author__ = "maurice & mg"
-__Comment__ = 'Kicad STEPUP(TM) (3D kicad board and models exported to STEP) for FreeCAD'
-___ver_ksu___ = "4.1.3.0 April 2017"
+__Comment__ = "Kicad STEPUP(TM) (3D kicad board and models exported to STEP) for FreeCAD"
+___ver_ksu___ = "4.1.3.0 April 2017"
___ver_GUI___ = "ksu-docked-v3.2"
-IDF_ImporterVersion="3.9.2"
+IDF_ImporterVersion = "3.9.2"
__Icon__ = "stepup.png"
@@ -524,80 +513,80 @@
global last_fp_path, last_pcb_path, plcmnt, xp, yp, exportFusing, exportS
global full_placement, shape_col, align_vrml_step_colors
global timer_Collisions, last_3d_path, expanded_view, mingui
-global textEdit_dim_base, textEdit_dim_hide #textEdit dimensions for hiding showing text content
+global textEdit_dim_base, textEdit_dim_hide # textEdit dimensions for hiding showing text content
global warning_nbr, original_filename, edge_width, load_sketch, grid_orig, dvm, pt_osx, pt_lnx, dqd, running_time
global addConstraints, precision, conv_offs, maxRadius, pad_nbr, use_pypro, accept_spline, maxDegree, maxSegments
global zfit, restore_specular_cls, preset_light
zfit = False
-restore_specular_cls=False
-preset_light= True #False
+restore_specular_cls = False
+preset_light = True # False
-maxRadius = 500.0 # 500mm maxRadius of arc from bspline
-pad_nbr = 1 #first nbr of fp pads
-use_pypro = False #False #enable/disable timestamp as python property; False=disabled -> use the Label
-accept_spline = True # include spline in PCB_Sketch for KiCAD >= v5.1
-maxDegree = 3 # spline degree for KiCAD integration
-maxSegments = 999 #for splines
+maxRadius = 500.0 # 500mm maxRadius of arc from bspline
+pad_nbr = 1 # first nbr of fp pads
+use_pypro = False # False #enable/disable timestamp as python property; False=disabled -> use the Label
+accept_spline = True # include spline in PCB_Sketch for KiCAD >= v5.1
+maxDegree = 3 # spline degree for KiCAD integration
+maxSegments = 999 # for splines
-conv_offs = 1.0 #conversion offset from decimils to mm pcb version >= 20171114
-original_filename=""
+conv_offs = 1.0 # conversion offset from decimils to mm pcb version >= 20171114
+original_filename = ""
edge_width = None
-load_sketch=True
-dvm = 3.0 # obsolete: discretizer multiplier factor
-dqd = 0.02 #discretize(QuasiDeflection=d) => gives a list of points with a maximum deflection 'd' to the edge (faster)
-precision = 0.1 # precision in spline or bezier conversion
-pt_osx=False #platform OSX
-pt_lnx=False #platform Linux
+load_sketch = True
+dvm = 3.0 # obsolete: discretizer multiplier factor
+dqd = 0.02 # discretize(QuasiDeflection=d) => gives a list of points with a maximum deflection 'd' to the edge (faster)
+precision = 0.1 # precision in spline or bezier conversion
+pt_osx = False # platform OSX
+pt_lnx = False # platform Linux
running_time = 0
-warning_nbr=10 #if missing more than 'warning_nbr' models, a warning will raise
- #set to -1 for skipping the test
-
-timer_Collisions= 3000 # ms
-mingui = 0 #Gui status: mingui = 1 -> minimized
-last_3d_path=u''
-expanded_view=0 # 0=not expanded; 1 edit expanded; 2 help expanded
-shape_col=(1.0, 0.0, 0.0)
-align_vrml_step_colors=True
-
-textEdit_dim_base=(176,36,305,453) #default value
-textEdit_dim_hide=(30000,30000,0,0) #hide value fake position
-
-last_pcb_path=u'' #py3
-exportS=True
-last_file_path=''
-pcb_path =u''
-resetP=True
+warning_nbr = 10 # if missing more than 'warning_nbr' models, a warning will raise
+# set to -1 for skipping the test
+
+timer_Collisions = 3000 # ms
+mingui = 0 # Gui status: mingui = 1 -> minimized
+last_3d_path = ""
+expanded_view = 0 # 0=not expanded; 1 edit expanded; 2 help expanded
+shape_col = (1.0, 0.0, 0.0)
+align_vrml_step_colors = True
+
+textEdit_dim_base = (176, 36, 305, 453) # default value
+textEdit_dim_hide = (30000, 30000, 0, 0) # hide value fake position
+
+last_pcb_path = "" # py3
+exportS = True
+last_file_path = ""
+pcb_path = ""
+resetP = True
global rot_wrl, test_flag, test_flag_pads
-rot_wrl=0.0
-#global module_3D_dir
-userCancelled = "Cancelled"
-userOK = "OK"
+rot_wrl = 0.0
+# global module_3D_dir
+userCancelled = "Cancelled"
+userOK = "OK"
show_mouse_pos = True
-#module_3D_dir="C:/Cad/Progetti_K/a_mod"
-min_val=0.001
-conflict_tolerance=1e-6 #volume tolerance
-#edge_tolerance=0.005 #edge coincidence tolerance (5000nm = 1/2 centesimo) base is mm
-edge_tolerance=0.01 #edge coincidence tolerance (500nm = 0.1 decimo) base is mm
-edge_tolerance_warning = 1e-6 #(1nm) base is mm
-apply_edge_tolerance = False #True
-simplifyComSolid = False #True this can be quite time consuming
-
-font_size=8
-bbox_r_col=(0.411765, 0.411765, 0.411765) #dimgrey
-bbox_c_col=(0.823529, 0.411765, 0.117647) #chocolate
-bbox_x_col=(0.862745, 0.862745, 0.862745) #gainsboro
-bbox_l_col=(0.333333, 0.333333, 0.333333) #sgidarkgrey
-bbox_IC_col=(0.156863, 0.156863, 0.156863) #sgiverydarkgrey
-bbox_default_col=(0.439216, 0.501961, 0.564706) #slategrey
-mat_section=u"""
+# module_3D_dir="C:/Cad/Progetti_K/a_mod"
+min_val = 0.001
+conflict_tolerance = 1e-6 # volume tolerance
+# edge_tolerance=0.005 #edge coincidence tolerance (5000nm = 1/2 centesimo) base is mm
+edge_tolerance = 0.01 # edge coincidence tolerance (500nm = 0.1 decimo) base is mm
+edge_tolerance_warning = 1e-6 # (1nm) base is mm
+apply_edge_tolerance = False # True
+simplifyComSolid = False # True this can be quite time consuming
+
+font_size = 8
+bbox_r_col = (0.411765, 0.411765, 0.411765) # dimgrey
+bbox_c_col = (0.823529, 0.411765, 0.117647) # chocolate
+bbox_x_col = (0.862745, 0.862745, 0.862745) # gainsboro
+bbox_l_col = (0.333333, 0.333333, 0.333333) # sgidarkgrey
+bbox_IC_col = (0.156863, 0.156863, 0.156863) # sgiverydarkgrey
+bbox_default_col = (0.439216, 0.501961, 0.564706) # slategrey
+mat_section = """
[Materials]
mat = enablematerials
;; VRML models to be or not exported with material properties
;mat = enablematerials\n;mat = nomaterials
"""
-dock_section=u"""
+dock_section = """
[docking]
dkmode = float
;;docking mode
@@ -605,14 +594,14 @@
;dkmode = right
;dkmode = float
"""
-turntable_section=u"""
+turntable_section = """
[turntable]
spin = enabled
;;turntable spin after loading
;spin = disabled
;spin = enabled
"""
-compound_section=u"""
+compound_section = """
[compound]
compound = allowed
;;allow compound for STEP models
@@ -620,7 +609,7 @@
;compound = disallowed
;compound = simplified
"""
-constraints_section=u"""
+constraints_section = """
[sketch_constraints]
constraints = all
;constraints = all
@@ -628,22 +617,22 @@
;constraints = none
;;constraints generated for pcb sketch
"""
-exporting_mode_section=u"""
+exporting_mode_section = """
[step_exporting_mode]
exporting_mode = hierarchy
;exporting_mode = hierarchy
;exporting_mode = flat
;exporting_mode = onelevel
-;;step exporting mode
+;;step exporting mode
"""
-font_section=u"""
+font_section = """
[fonts]
font_size = 8
;;font size for ksu widget
"""
-links_importing_mode_section=u"""
+links_importing_mode_section = """
[links_importing_mode]
importing_mode = standard
;importing_mode = links
@@ -652,119 +641,124 @@
"""
global ini_vars, num_min_lines
-ini_vars=[]
-for i in range (0,20):
- ini_vars.append('-')
-num_min_lines=22 #min numbers of ini lines for a ksu-config file
+ini_vars = []
+for i in range(20):
+ ini_vars.append("-")
+num_min_lines = 22 # min numbers of ini lines for a ksu-config file
-#FreeCAD.Console.PrintError(len(ini_vars))
-#FreeCAD.Console.PrintWarning('\n')
+# FreeCAD.Console.PrintError(len(ini_vars))
+# FreeCAD.Console.PrintWarning('\n')
global extrude_holes
-test_flag=False
-#test_flag=True
-test_flag_exit=False #True 4 testing
-test_flag_pads=False #True 4 testing
-remove_pcbPad=True #False 4 testing
-close_doc=False
-
-show_border=False #False
-show_data=False #False
-show_debug=False #False
-
-show_shapes=False
-disable_cutting=False
+test_flag = False
+# test_flag=True
+test_flag_exit = False # True 4 testing
+test_flag_pads = False # True 4 testing
+remove_pcbPad = True # False 4 testing
+close_doc = False
+
+show_border = False # False
+show_data = False # False
+show_debug = False # False
+
+show_shapes = False
+disable_cutting = False
# enable_materials=True not used
-test_extrude=False #False
-holes_solid=False #False #cutting sketch face with faces or solid drills (sd very intensive i.e. with drills=-1 (vias) + memory leak)
-extrude_holes = True # fixing coplanar shapes cut for holes
-emn_version=3.0
-show_messages=True #False 4 testing
-#show_messages=False # mauitest
-full_placement=True # for offset in xyz and rotation in xyz
+test_extrude = False # False
+holes_solid = False # False #cutting sketch face with faces or solid drills (sd very intensive i.e. with drills=-1 (vias) + memory leak)
+extrude_holes = True # fixing coplanar shapes cut for holes
+emn_version = 3.0
+show_messages = True # False 4 testing
+# show_messages=False # mauitest
+full_placement = True # for offset in xyz and rotation in xyz
# FreeCAD.Console.PrintWarning(full_placement)
# FreeCAD.Console.PrintWarning('\n')
global disable_VBO
-disable_VBO = True # False to test crash
-if disable_VBO == False:
+disable_VBO = True # False to test crash
+if not disable_VBO:
FreeCAD.Console.PrintWarning("VBO check disabled\n")
global disable_PoM_Observer
disable_PoM_Observer = False
try:
- import PartOMagic
- import PartOMagic.Gui.Observer as Observer
+ from PartOMagic.Gui import Observer
+
disable_PoM_Observer = True
FreeCAD.Console.PrintWarning("PoM present\n")
except:
FreeCAD.Console.PrintWarning("PoM not present\n")
+
##
def say_inline(msg):
- FreeCAD.Console.PrintMessage(msg+' ')
+ FreeCAD.Console.PrintMessage(msg + " ")
+
def say(msg):
FreeCAD.Console.PrintMessage(msg)
- FreeCAD.Console.PrintMessage('\n')
+ FreeCAD.Console.PrintMessage("\n")
+
def sayw(msg):
FreeCAD.Console.PrintWarning(msg)
- FreeCAD.Console.PrintWarning('\n')
-
+ FreeCAD.Console.PrintWarning("\n")
+
+
def sayerr(msg):
FreeCAD.Console.PrintError(msg)
- FreeCAD.Console.PrintMessage('\n')
+ FreeCAD.Console.PrintMessage("\n")
+
+
##
global use_AppPart, use_Links, use_LinkGroups
-use_AppPart=False # False
-use_Links=False
+use_AppPart = False # False
+use_Links = False
use_LinkGroups = False
-if 'LinkView' in dir(FreeCADGui):
+if "LinkView" in dir(FreeCADGui):
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if prefs.GetBool('asm3_linkGroups'):
+ if prefs.GetBool("asm3_linkGroups"):
use_LinkGroups = True
- use_Links=True #False
- sayw('using \'LinkGroups\' and \'Links\'')
- elif prefs.GetBool('asm3_links'):
- use_Links=True #False
- sayw('using \'Part\' container and \'Links\'')
+ use_Links = True # False
+ sayw("using 'LinkGroups' and 'Links'")
+ elif prefs.GetBool("asm3_links"):
+ use_Links = True # False
+ sayw("using 'Part' container and 'Links'")
else:
use_LinkGroups = False
- sayw('using \'Part\' container')
+ sayw("using 'Part' container")
else:
use_LinkGroups = False
- sayw('using \'Part\' container')
+ sayw("using 'Part' container")
-#
global FC_export_min_version
-FC_export_min_version="11670" #11670 latest JM
+FC_export_min_version = "11670" # 11670 latest JM
+
def ZoomFitThread():
- FreeCAD.Console.PrintWarning('thread ViewFitting\n')
+ FreeCAD.Console.PrintWarning("thread ViewFitting\n")
if FreeCAD.ActiveDocument is not None:
FreeCADGui.SendMsgToActiveView("ViewFit")
- #stop
+ # stop
+
-#
def collaps_Tree():
- FreeCAD.Console.PrintWarning('thread Collapsing\n')
+ FreeCAD.Console.PrintWarning("thread Collapsing\n")
if FreeCAD.ActiveDocument is not None:
mw1 = FreeCADGui.getMainWindow()
treesSel = mw1.findChildren(QtGui.QTreeWidget)
for tree in treesSel:
items = tree.selectedItems()
for item in items:
- if item.isExpanded() == True:
- collapse = True
- print ("collapsing")
+ if item.isExpanded():
+ print("collapsing")
tree.collapseItem(item)
FreeCADGui.Selection.clearSelection()
-#
+
##--------------------------------------------------------------------------------------
-py2=False
+py2 = False
try: ## maui py3
unicode = unicode
except NameError:
@@ -772,117 +766,111 @@ def collaps_Tree():
str = str
unicode = str
bytes = bytes
- basestring = (str,bytes)
+ basestring = (str, bytes)
else:
# 'unicode' exists, must be Python 2
str = str
unicode = unicode
bytes = str
basestring = basestring
- py2=True
+ py2 = True
+
def isConstruction(geo):
- if hasattr(geo,'Construction'):
+ if hasattr(geo, "Construction"):
# print(geo.Construction,'geo.Construction')
return geo.Construction
- else:
- # print('geo.Content',geo.Content)
- if 'geometryModeFlags="00000000000000000000000000000010"' in geo.Content:
- # print('geometryModeFlags', True)
- return True
- else:
- # print('geometryModeFlags', False)
- return False
-#
+ # print('geo.Content',geo.Content)
+ return 'geometryModeFlags="00000000000000000000000000000010"' in geo.Content
-PY3 = sys.version_info[0] == 3 # maui @realthunder fcad_pcb py3
-if PY3:
- string_types = str,
-else:
- string_types = basestring,
+
+PY3 = sys.version_info[0] >= 3 # maui @realthunder fcad_pcb py3
+string_types = (str,) if PY3 else (basestring,)
###
# sexp
# maui
-import fcad_parser
-from fcad_parser import KicadPCB,SexpList
import kicad_parser
+from fcad_parser import KicadPCB
+
###
-def rotatePoint(r,sa,da,c):
+def rotatePoint(r, sa, da, c):
# sa, da in degrees
- x = c[0] - cos(radians(sa+da)) * r
- y = c[1] - sin(radians(sa+da)) * r
- return [x,y]
+ x = c[0] - cos(radians(sa + da)) * r
+ y = c[1] - sin(radians(sa + da)) * r
+ return [x, y]
+
+
###
def getFCversion():
- FC_majorV=int(float(FreeCAD.Version()[0]))
- FC_minorV=int(float(FreeCAD.Version()[1]))
+ FC_majorV = int(float(FreeCAD.Version()[0]))
+ FC_minorV = int(float(FreeCAD.Version()[1]))
try:
- FC_git_Nbr=int (float(FreeCAD.Version()[2].strip(" (Git)").split(' ')[0])) #+int(FreeCAD.Version()[2].strip(" (Git)").split(' ')[1])
+ FC_git_Nbr = int(
+ float(FreeCAD.Version()[2].strip(" (Git)").split(" ")[0]),
+ ) # +int(FreeCAD.Version()[2].strip(" (Git)").split(' ')[1])
except:
- FC_git_Nbr=0
- return FC_majorV,FC_minorV,FC_git_Nbr
-
-FC_majorV,FC_minorV,FC_git_Nbr=getFCversion()
-FreeCAD.Console.PrintWarning('FC Version '+str(FC_majorV)+str(FC_minorV)+"-"+str(FC_git_Nbr)+'\n')
-if FC_majorV == 0 and FC_minorV == 17:
- if FC_git_Nbr >= int(FC_export_min_version):
- use_AppPart=True
-#if FreeCAD.Version()[2] == 'Unknown': #workaround for local building
+ FC_git_Nbr = 0
+ return FC_majorV, FC_minorV, FC_git_Nbr
+
+
+FC_majorV, FC_minorV, FC_git_Nbr = getFCversion()
+FreeCAD.Console.PrintWarning("FC Version " + str(FC_majorV) + str(FC_minorV) + "-" + str(FC_git_Nbr) + "\n")
+if FC_majorV == 0 and FC_minorV == 17 and FC_git_Nbr >= int(FC_export_min_version):
+ use_AppPart = True
+# if FreeCAD.Version()[2] == 'Unknown': #workaround for local building
# use_AppPart=True
if FC_majorV > 0:
- use_AppPart=True
+ use_AppPart = True
if FC_majorV == 0 and FC_minorV > 17:
- #if FC_git_Nbr >= int(FC_export_min_version):
- use_AppPart=True
-#if use_AppPart:
+ # if FC_git_Nbr >= int(FC_export_min_version):
+ use_AppPart = True
+# if use_AppPart:
# FreeCAD.Console.PrintWarning("creating hierarchy\n")
-if int(FC_majorV) <= 0:
- if int(FC_minorV) == 15:
- load_sketch=False
-
+if int(FC_majorV) <= 0 and int(FC_minorV) == 15:
+ load_sketch = False
+
global force_oldGroups
-force_oldGroups=False # False
+force_oldGroups = False # False
-try:
- from freecad.asm3 import assembly as asm
- #use_Links=True #False
- FreeCAD.Console.PrintWarning('Asm3 WB present\n')
-except:
- pass
- #FreeCAD.Console.PrintWarning('Asm3 WB not present\n')
+with contextlib.suppress(Exception):
+ FreeCAD.Console.PrintWarning("Asm3 WB present\n")
+ # FreeCAD.Console.PrintWarning('Asm3 WB not present\n')
global export_board_2step
-#export_board_2step=False
-save_temp_data=False
+# export_board_2step=False
+save_temp_data = False
global ignore_utf8
-ignore_utf8=False
+ignore_utf8 = False
global ignore_utf8_incfg
-ignore_utf8_incfg=True
+ignore_utf8_incfg = True
global animate_result
-animate_result=True #False turntable
+animate_result = True # False turntable
global allow_compound
-allow_compound='False' #allow compound in ksu
+allow_compound = "False" # allow compound in ksu
global apply_reflex
-apply_reflex=True #True adds shininess for Single Color Shapes valid ONLY if turntable is enabled
+apply_reflex = True # True adds shininess for Single Color Shapes valid ONLY if turntable is enabled
global apply_reflex_all
-apply_reflex_all=False #True not suggested wip simulate shininess for faces
+apply_reflex_all = False # True not suggested wip simulate shininess for faces
global force_transparency
-force_transparency = False #True for testing wip
+force_transparency = False # True for testing wip
global apply_light
-apply_light=False #True not suggested wip add light up and down
+apply_light = False # True not suggested wip add light up and down
# disabling pcurves
paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/General")
paramGet.SetInt("WriteSurfaceCurveMode", 0)
-current_milli_time = lambda: int(round(time.time() * 1000))
-Materials=True
+def current_milli_time():
+ return round(time.time() * 1000)
+
+
+Materials = True
## "PIN-01";"metal grey pins"
## "PIN-02";"gold pins"
## "IC-BODY-EPOXY-04";"black body"
@@ -896,9 +884,9 @@ def getFCversion():
## "IC-LABEL-01";"light brown label"
## LED-GREEN, LED-RED, LED-BLUE
-as_is=""
+as_is = ""
-metal_grey_pins="""material DEF PIN-01 Material {
+metal_grey_pins = """material DEF PIN-01 Material {
ambientIntensity 0.271
diffuseColor 0.824 0.820 0.781
specularColor 0.328 0.258 0.172
@@ -906,9 +894,9 @@ def getFCversion():
shininess 0.70
transparency 0.0
}"""
-
+
# http://vrmlstuff.free.fr/materials/
-metal_grey="""material DEF MET-01 Material {
+metal_grey = """material DEF MET-01 Material {
ambientIntensity 0.249999
diffuseColor 0.298 0.298 0.298
specularColor 0.398 0.398 0.398
@@ -916,8 +904,8 @@ def getFCversion():
shininess 0.056122
transparency 0.0
}"""
-
-gold_pins="""material DEF PIN-02 Material {
+
+gold_pins = """material DEF PIN-02 Material {
ambientIntensity 0.379
diffuseColor 0.859 0.738 0.496
specularColor 0.137 0.145 0.184
@@ -926,7 +914,7 @@ def getFCversion():
transparency 0.0
}"""
-black_body="""material DEF IC-BODY-EPOXY-04 Material {
+black_body = """material DEF IC-BODY-EPOXY-04 Material {
ambientIntensity 0.293
diffuseColor 0.148 0.145 0.145
specularColor 0.180 0.168 0.160
@@ -935,7 +923,7 @@ def getFCversion():
transparency 0.0
}"""
-resistor_black_body="""material DEF RES-SMD-01 Material {
+resistor_black_body = """material DEF RES-SMD-01 Material {
diffuseColor 0.082 0.086 0.094
emissiveColor 0.000 0.000 0.000
specularColor 0.066 0.063 0.063
@@ -944,7 +932,7 @@ def getFCversion():
shininess 0.3
}"""
-dark_grey_body="""material DEF CAP-CERAMIC-05 Material {
+dark_grey_body = """material DEF CAP-CERAMIC-05 Material {
ambientIntensity 0.179
diffuseColor 0.273 0.273 0.273
specularColor 0.203 0.188 0.176
@@ -953,7 +941,7 @@ def getFCversion():
transparency 0.0
}"""
-grey_body="""material DEF IC-BODY-EPOXY-01 Material {
+grey_body = """material DEF IC-BODY-EPOXY-01 Material {
ambientIntensity 0.117
diffuseColor 0.250 0.262 0.281
specularColor 0.316 0.281 0.176
@@ -962,7 +950,7 @@ def getFCversion():
transparency 0.0
}"""
-brown_body="""material DEF CAP-CERAMIC-06 Material {
+brown_body = """material DEF CAP-CERAMIC-06 Material {
ambientIntensity 0.453
diffuseColor 0.379 0.270 0.215
specularColor 0.223 0.223 0.223
@@ -971,7 +959,7 @@ def getFCversion():
transparency 0.0
}"""
-light_brown_body="""material DEF RES-THT-01 Material {
+light_brown_body = """material DEF RES-THT-01 Material {
ambientIntensity 0.149
diffuseColor 0.883 0.711 0.492
specularColor 0.043 0.121 0.281
@@ -980,7 +968,7 @@ def getFCversion():
transparency 0.0
}"""
-blue_body="""material DEF PLASTIC-BLUE-01 Material {
+blue_body = """material DEF PLASTIC-BLUE-01 Material {
ambientIntensity 0.565
diffuseColor 0.137 0.402 0.727
specularColor 0.359 0.379 0.270
@@ -989,7 +977,7 @@ def getFCversion():
transparency 0.0
}"""
-green_body="""material DEF PLASTIC-GREEN-01 Material {
+green_body = """material DEF PLASTIC-GREEN-01 Material {
ambientIntensity 0.315
diffuseColor 0.340 0.680 0.445
specularColor 0.176 0.105 0.195
@@ -998,7 +986,7 @@ def getFCversion():
transparency 0.0
}"""
-orange_body="""material DEF PLASTIC-ORANGE-01 Material {
+orange_body = """material DEF PLASTIC-ORANGE-01 Material {
ambientIntensity 0.284
diffuseColor 0.809 0.426 0.148
specularColor 0.039 0.102 0.145
@@ -1007,7 +995,7 @@ def getFCversion():
transparency 0.0
}"""
-red_body="""material DEF RED-BODY Material {
+red_body = """material DEF RED-BODY Material {
ambientIntensity 0.683
diffuseColor 0.700 0.100 0.050
emissiveColor 0.000 0.000 0.000
@@ -1016,7 +1004,7 @@ def getFCversion():
transparency 0.0
}"""
-pink_body="""material DEF CAP-CERAMIC-02 Material {
+pink_body = """material DEF CAP-CERAMIC-02 Material {
ambientIntensity 0.683
diffuseColor 0.578 0.336 0.352
specularColor 0.105 0.273 0.270
@@ -1025,7 +1013,7 @@ def getFCversion():
transparency 0.0
}"""
-yellow_body="""material DEF PLASTIC-YELLOW-01 Material {
+yellow_body = """material DEF PLASTIC-YELLOW-01 Material {
ambientIntensity 0.522
diffuseColor 0.832 0.680 0.066
specularColor 0.160 0.203 0.320
@@ -1034,7 +1022,7 @@ def getFCversion():
transparency 0.0
}"""
-white_body="""material DEF PLASTIC-WHITE-01 Material {
+white_body = """material DEF PLASTIC-WHITE-01 Material {
ambientIntensity 0.494
diffuseColor 0.895 0.891 0.813
specularColor 0.047 0.055 0.109
@@ -1043,7 +1031,7 @@ def getFCversion():
transparency 0.0
}"""
-light_brown_label="""material DEF IC-LABEL-01 Material {
+light_brown_label = """material DEF IC-LABEL-01 Material {
ambientIntensity 0.082
diffuseColor 0.691 0.664 0.598
specularColor 0.000 0.000 0.000
@@ -1052,7 +1040,7 @@ def getFCversion():
transparency 0.0
}"""
-led_red="""material DEF LED-RED Material {
+led_red = """material DEF LED-RED Material {
ambientIntensity 0.789
diffuseColor 0.700 0.100 0.050
emissiveColor 0.000 0.000 0.000
@@ -1061,7 +1049,7 @@ def getFCversion():
transparency 0.15
}"""
-led_green="""material DEF LED-GREEN Material {
+led_green = """material DEF LED-GREEN Material {
ambientIntensity 0.789
diffuseColor 0.400 0.700 0.150
emissiveColor 0.000 0.000 0.000
@@ -1070,7 +1058,7 @@ def getFCversion():
transparency 0.15
}"""
-led_blue="""material DEF LED-BLUE Material {
+led_blue = """material DEF LED-BLUE Material {
ambientIntensity 0.789
diffuseColor 0.100 0.250 0.700
emissiveColor 0.000 0.000 0.000
@@ -1079,7 +1067,7 @@ def getFCversion():
transparency 0.15
}"""
-led_yellow="""material DEF LED-YELLOW Material {
+led_yellow = """material DEF LED-YELLOW Material {
ambientIntensity 0.522
diffuseColor 0.98 0.840 0.066
specularColor 0.160 0.203 0.320
@@ -1088,7 +1076,7 @@ def getFCversion():
transparency 0.15
}"""
-led_white="""material DEF LED-WHITE Material {
+led_white = """material DEF LED-WHITE Material {
ambientIntensity 0.494
diffuseColor 0.895 0.891 0.813
specularColor 0.047 0.055 0.109
@@ -1097,7 +1085,7 @@ def getFCversion():
transparency 0.15
}"""
-led_grey="""material DEF LED-GREY Material {
+led_grey = """material DEF LED-GREY Material {
ambientIntensity 0.494
diffuseColor 0.27 0.25 0.27
specularColor 0.5 0.5 0.6
@@ -1106,7 +1094,7 @@ def getFCversion():
transparency 0.15
}"""
-led_black="""material DEF LED-BLACK Material {
+led_black = """material DEF LED-BLACK Material {
ambientIntensity 0.494
diffuseColor 0.1 0.05 0.1
specularColor 0.6 0.5 0.6
@@ -1115,7 +1103,7 @@ def getFCversion():
transparency 0.15
}"""
-glass_grey="""material DEF GLASS-19 Material {
+glass_grey = """material DEF GLASS-19 Material {
ambientIntensity 0.2018212
diffuseColor 0.400769 0.441922 0.459091
specularColor 0.573887 0.649271 0.810811
@@ -1124,7 +1112,7 @@ def getFCversion():
transparency 0.37
}"""
-glass_gold="""material DEF GLASS-29 Material {
+glass_gold = """material DEF GLASS-29 Material {
ambientIntensity 0.379
diffuseColor 0.859 0.738 0.496
specularColor 0.137 0.145 0.184
@@ -1133,7 +1121,7 @@ def getFCversion():
transparency 0.39
}"""
-glass_blue="""material DEF GLASS-13 Material {
+glass_blue = """material DEF GLASS-13 Material {
ambientIntensity 0.250000
diffuseColor 0.000000 0.631244 0.748016
specularColor 0.915152 0.915152 0.915152
@@ -1142,7 +1130,7 @@ def getFCversion():
transparency 0.39
}"""
-glass_green="""material DEF GLASS-GREEN Material {
+glass_green = """material DEF GLASS-GREEN Material {
ambientIntensity 0.250000
diffuseColor 0.000000 0.75 0.44
specularColor 0.915152 0.915152 0.915152
@@ -1151,7 +1139,7 @@ def getFCversion():
transparency 0.39
}"""
-glass_orange="""material DEF GLASS-ORANGE Material {
+glass_orange = """material DEF GLASS-ORANGE Material {
ambientIntensity 0.250000
diffuseColor 0.75 0.44 0.000000
specularColor 0.915152 0.915152 0.915152
@@ -1160,16 +1148,16 @@ def getFCversion():
transparency 0.39
}"""
-pcb_green="""material DEF BOARD-GREEN-02 Material {
+pcb_green = """material DEF BOARD-GREEN-02 Material {
ambientIntensity 1
diffuseColor 0.07 0.3 0.12
specularColor 0.07 0.3 0.12
emissiveColor 0.0 0.0 0.0
shininess 0.40
transparency 0.0
- }"""
+ }"""
-pcb_blue="""material DEF BOARD-BLUE-01 Material {
+pcb_blue = """material DEF BOARD-BLUE-01 Material {
ambientIntensity 1
diffuseColor 0.07 0.12 0.3
specularColor 0.07 0.12 0.3
@@ -1178,7 +1166,7 @@ def getFCversion():
transparency 0.0
}"""
-pcb_black="""material DEF BOARD-BLACK-03 Material {
+pcb_black = """material DEF BOARD-BLACK-03 Material {
ambientIntensity 1
diffuseColor 0.16 0.16 0.16
specularColor 0.16 0.16 0.16
@@ -1187,7 +1175,7 @@ def getFCversion():
transparency 0.0
}"""
-metal_aluminum="""material DEF MET-ALUMINUM Material {
+metal_aluminum = """material DEF MET-ALUMINUM Material {
ambientIntensity 0.256000
diffuseColor 0.372322 0.371574 0.373173
specularColor 0.556122 0.554201 0.556122
@@ -1205,7 +1193,7 @@ def getFCversion():
# shininess 0.107143
# transparency 0.0
# }"""
-metal_bronze="""material DEF MET-BRONZE Material {
+metal_bronze = """material DEF MET-BRONZE Material {
ambientIntensity 0.022727
diffuseColor 0.714 0.4284 0.18144
specularColor 0.393548 0.271906 0.166721
@@ -1213,12 +1201,12 @@ def getFCversion():
shininess 0.2
transparency 0.0
}"""
-
-#bronze 0.2125 0.1275 0.054 0.714 0.4284 0.18144 0.393548 0.271906 0.166721 0.2
-#http://devernay.free.fr/cours/opengl/materials.html
-#silver 0.19225 0.19225 0.19225 0.50754 0.50754 0.50754 0.508273 0.508273 0.508273 0.4
-metal_silver="""material DEF MET-SILVER Material {
+# bronze 0.2125 0.1275 0.054 0.714 0.4284 0.18144 0.393548 0.271906 0.166721 0.2
+# http://devernay.free.fr/cours/opengl/materials.html
+
+# silver 0.19225 0.19225 0.19225 0.50754 0.50754 0.50754 0.508273 0.508273 0.508273 0.4
+metal_silver = """material DEF MET-SILVER Material {
ambientIntensity 0.022727
diffuseColor 0.50754 0.50754 0.50754
specularColor 0.508273 0.508273 0.508273
@@ -1227,7 +1215,7 @@ def getFCversion():
transparency 0.0
}"""
-metal_copper="""material DEF MET-COPPER Material {
+metal_copper = """material DEF MET-COPPER Material {
ambientIntensity 0.022727
diffuseColor 0.7038 0.27048 0.0828
specularColor 0.780612 0.37 0.000000
@@ -1235,140 +1223,245 @@ def getFCversion():
shininess 0.2
transparency 0.0
}"""
-#specularColor 0.780612 0.598604 0.000000
-
-material_properties_names=["as is","metal grey pins","metal grey","gold pins",
- "black body","resistor black body","grey body","dark grey body","brown body",\
- "light brown body","blue body","green body","orange body","red_body",\
- "pink body","yellow body","white body",\
- "light brown label",\
- "led red","led green","led blue","led yellow","led white", "led grey", "led black",\
- "glass grey","glass gold","glass blue","glass green","glass orange", \
- "pcb green", "pcb blue", "pcb black",\
- "metal aluminum", "metal bronze", "metal silver", "metal copper"]
-
-material_properties=[as_is, metal_grey_pins, metal_grey, gold_pins,\
- black_body,resistor_black_body, grey_body,dark_grey_body,brown_body,\
- light_brown_body,blue_body, green_body,orange_body,red_body,\
- pink_body,yellow_body,white_body,
- light_brown_label,\
- led_red,led_green,led_blue,led_yellow,led_white, led_grey, led_black, \
- glass_grey, glass_gold, glass_blue, glass_green,glass_orange, \
- pcb_green, pcb_blue, pcb_black,\
- metal_aluminum, metal_bronze, metal_silver, metal_copper]
-
-material_properties_diffuse=[(0.,0.,0.,0.),(0.824,0.820,0.781,0.),( 0.298, 0.298, 0.298,0.),(0.859,0.738,0.496,0.), \
- (0.148, 0.145, 0.145,0.), (0.082, 0.086, 0.094,0.),(0.250, 0.262, 0.281,0.), (0.273, 0.273, 0.273,0.), (0.379, 0.270, 0.215,0.), \
- (0.883, 0.711, 0.492,0.), (0.137, 0.402, 0.727,0.),(0.340, 0.680, 0.445,0.), (0.809, 0.426, 0.148,0.), (0.700, 0.100, 0.050,0.), \
- (0.578, 0.336, 0.352,0.), (0.832, 0.680, 0.066,0.), (0.895, 0.891, 0.813,0.), \
- (0.691, 0.664, 0.598,0.), \
- (0.700, 0.100, 0.050,0.15), (0.400, 0.700, 0.150,0.15), (0.100, 0.250, 0.700,0.15), (0.98, 0.840, 0.066,0.15), (0.895, 0.891, 0.813,0.15),(0.27, 0.25, 0.27,0.15), (0.1, 0.05, 0.1,0.15),\
- (0.400769, 0.441922, 0.459091,0.37), (0.859, 0.738, 0.496,0.39), (0.000000, 0.631244, 0.748016,0.39), (0.000000, 0.75, 0.44,0.39), (0.75, 0.44, 0.0,0.39), \
- (0.07, 0.3, 0.12,0.), (0.07, 0.12, 0.3,0.), (0.16, 0.16, 0.16,0.), \
- (0.372322, 0.371574, 0.373173,0.), (0.714, 0.4284, 0.18144,0.), (0.50754, 0.50754, 0.50754,0.), (0.7038, 0.27048, 0.0828,0.)] # (0.314286, 0.074365, 0.000000)]
-
-#FreeCAD.Console.PrintMessage (len (material_properties_names))
-#FreeCAD.Console.PrintMessage (len (material_properties))
-#FreeCAD.Console.PrintMessage (len (material_properties_diffuse))
-#stop
-
-material_definitions=""
+# specularColor 0.780612 0.598604 0.000000
+
+material_properties_names = [
+ "as is",
+ "metal grey pins",
+ "metal grey",
+ "gold pins",
+ "black body",
+ "resistor black body",
+ "grey body",
+ "dark grey body",
+ "brown body",
+ "light brown body",
+ "blue body",
+ "green body",
+ "orange body",
+ "red_body",
+ "pink body",
+ "yellow body",
+ "white body",
+ "light brown label",
+ "led red",
+ "led green",
+ "led blue",
+ "led yellow",
+ "led white",
+ "led grey",
+ "led black",
+ "glass grey",
+ "glass gold",
+ "glass blue",
+ "glass green",
+ "glass orange",
+ "pcb green",
+ "pcb blue",
+ "pcb black",
+ "metal aluminum",
+ "metal bronze",
+ "metal silver",
+ "metal copper",
+]
+
+material_properties = [
+ as_is,
+ metal_grey_pins,
+ metal_grey,
+ gold_pins,
+ black_body,
+ resistor_black_body,
+ grey_body,
+ dark_grey_body,
+ brown_body,
+ light_brown_body,
+ blue_body,
+ green_body,
+ orange_body,
+ red_body,
+ pink_body,
+ yellow_body,
+ white_body,
+ light_brown_label,
+ led_red,
+ led_green,
+ led_blue,
+ led_yellow,
+ led_white,
+ led_grey,
+ led_black,
+ glass_grey,
+ glass_gold,
+ glass_blue,
+ glass_green,
+ glass_orange,
+ pcb_green,
+ pcb_blue,
+ pcb_black,
+ metal_aluminum,
+ metal_bronze,
+ metal_silver,
+ metal_copper,
+]
+
+material_properties_diffuse = [
+ (0.0, 0.0, 0.0, 0.0),
+ (0.824, 0.820, 0.781, 0.0),
+ (0.298, 0.298, 0.298, 0.0),
+ (0.859, 0.738, 0.496, 0.0),
+ (0.148, 0.145, 0.145, 0.0),
+ (0.082, 0.086, 0.094, 0.0),
+ (0.250, 0.262, 0.281, 0.0),
+ (0.273, 0.273, 0.273, 0.0),
+ (0.379, 0.270, 0.215, 0.0),
+ (0.883, 0.711, 0.492, 0.0),
+ (0.137, 0.402, 0.727, 0.0),
+ (0.340, 0.680, 0.445, 0.0),
+ (0.809, 0.426, 0.148, 0.0),
+ (0.700, 0.100, 0.050, 0.0),
+ (0.578, 0.336, 0.352, 0.0),
+ (0.832, 0.680, 0.066, 0.0),
+ (0.895, 0.891, 0.813, 0.0),
+ (0.691, 0.664, 0.598, 0.0),
+ (0.700, 0.100, 0.050, 0.15),
+ (0.400, 0.700, 0.150, 0.15),
+ (0.100, 0.250, 0.700, 0.15),
+ (0.98, 0.840, 0.066, 0.15),
+ (0.895, 0.891, 0.813, 0.15),
+ (0.27, 0.25, 0.27, 0.15),
+ (0.1, 0.05, 0.1, 0.15),
+ (0.400769, 0.441922, 0.459091, 0.37),
+ (0.859, 0.738, 0.496, 0.39),
+ (0.000000, 0.631244, 0.748016, 0.39),
+ (0.000000, 0.75, 0.44, 0.39),
+ (0.75, 0.44, 0.0, 0.39),
+ (0.07, 0.3, 0.12, 0.0),
+ (0.07, 0.12, 0.3, 0.0),
+ (0.16, 0.16, 0.16, 0.0),
+ (0.372322, 0.371574, 0.373173, 0.0),
+ (0.714, 0.4284, 0.18144, 0.0),
+ (0.50754, 0.50754, 0.50754, 0.0),
+ (0.7038, 0.27048, 0.0828, 0.0),
+] # (0.314286, 0.074365, 0.000000)]
+
+# FreeCAD.Console.PrintMessage (len (material_properties_names))
+# FreeCAD.Console.PrintMessage (len (material_properties))
+# FreeCAD.Console.PrintMessage (len (material_properties_diffuse))
+# stop
+
+material_definitions = ""
for mat in material_properties[1:]:
- material_definitions+="Shape {\n appearance Appearance {"+mat+"\n }\n}\n"
+ material_definitions += "Shape {\n appearance Appearance {" + mat + "\n }\n}\n"
-material_ids=[]
+material_ids = []
material_ids.append("")
for mat in material_properties[1:]:
- m = re.search('DEF\s(.+?)\sMaterial', mat)
+ m = re.search(r"DEF\s(.+?)\sMaterial", mat)
if m:
found = m.group(1)
- #say(found)
+ # say(found)
material_ids.append(found)
-#say(material_ids)
-#say (material_definitions)
+# say(material_ids)
+# say (material_definitions)
+
def clear_console():
- #clearing previous messages
- mw=FreeCADGui.getMainWindow()
- c=mw.findChild(QtGui.QPlainTextEdit, "Python console")
+ # clearing previous messages
+ mw = FreeCADGui.getMainWindow()
+ c = mw.findChild(QtGui.QPlainTextEdit, "Python console")
c.clear()
- r=mw.findChild(QtGui.QTextEdit, "Report view")
+ r = mw.findChild(QtGui.QTextEdit, "Report view")
r.clear()
-#if not Mod_ENABLED:
+
+# if not Mod_ENABLED:
if 0:
clear_console()
-
+
# points: [Vector, Vector, ...]
# faces: [(pi, pi, pi), ], pi: point index
# color: (Red, Green, Blue), values range from 0 to 1.0
-Mesh = namedtuple('Mesh', ['points', 'faces', 'color', 'transp'])
+Mesh = namedtuple("Mesh", ["points", "faces", "color", "transp"]) # noqa: F811
+import contextlib
from sys import platform as _platform
# window GUI dimensions parameters
if _platform == "linux" or _platform == "linux2":
- # linux
- pt_lnx=True
- sizeXmin=172;sizeYmin=34+34
- sizeX=172;sizeY=516 #536
- sizeXright=172;sizeYright=536 #556
+ # linux
+ pt_lnx = True
+ sizeXmin = 172
+ sizeYmin = 34 + 34
+ sizeX = 172
+ sizeY = 516 # 536
+ sizeXright = 172
+ sizeYright = 536 # 556
else:
- sizeXmin=172;sizeYmin=34
- sizeX=172;sizeY=482#502
- sizeXright=172;sizeYright=502#522
+ sizeXmin = 172
+ sizeYmin = 34
+ sizeX = 172
+ sizeY = 482 # 502
+ sizeXright = 172
+ sizeYright = 502 # 522
if _platform == "darwin":
- pt_osx=True
+ pt_osx = True
## # MAC OS X
##elif _platform == "win32":
## # Windows
-#sizeXmin=172;sizeYmin=30+34
-sizeXMax=487 #487
-btn_sizeX=32;btn_sizeY=32;
-chkb_sizeX=20;chkb_sizeY=20;
-btn_sm_sizeX=20;btn_sm_sizeY=20;
-btn_md_sizeX=26;btn_md_sizeY=26;
+# sizeXmin=172;sizeYmin=30+34
+sizeXMax = 487 # 487
+btn_sizeX = 32
+btn_sizeY = 32
+chkb_sizeX = 20
+chkb_sizeY = 20
+btn_sm_sizeX = 20
+btn_sm_sizeY = 20
+btn_md_sizeX = 26
+btn_md_sizeY = 26
+
def close_ksu():
- #def closeEvent(self, e):
- spc="""****************************************************************************
"""
- msg=translate("Close",
- "Do you want to quit? "
- "Have you saved your STEP artwork?
"
- )
- #confirm on exit
+ # def closeEvent(self, e):
+ msg = translate("Close", "Do you want to quit? Have you saved your STEP artwork?
")
+ # confirm on exit
QtGui.QApplication.restoreOverrideCursor()
- #self.setGeometry(25, 250, 500, 500)
- #self.setWindowState(QtCore.Qt.WindowMinimized)
- res=''
- if test_flag_exit==False:
+ # self.setGeometry(25, 250, 500, 500)
+ # self.setWindowState(QtCore.Qt.WindowMinimized)
+ res = ""
+ if not test_flag_exit:
QtGui.QApplication.restoreOverrideCursor()
res = QtGui.QMessageBox.question(
- None,translate("Close", "Close"),msg,QtGui.QMessageBox.Yes|QtGui.QMessageBox.No
+ None,
+ translate("Close", "Close"),
+ msg,
+ QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
)
if res is not QtGui.QMessageBox.No:
- #e.ignore()
+ # e.ignore()
# KSUWidget.close()
KSUWidget.deleteLater()
- #self.setWindowState(QtCore.Qt.WindowActive)
- doc=FreeCAD.ActiveDocument
+ # self.setWindowState(QtCore.Qt.WindowActive)
+ doc = FreeCAD.ActiveDocument
if doc is not None:
FreeCAD.setActiveDocument(doc.Name)
- #FreeCAD.ActiveDocument=FreeCAD.getDocument(doc.Label)
- #FreeCADGui.ActiveDocument=FreeCADGui.getDocument(doc.Label)
- if close_doc==True:
+ # FreeCAD.ActiveDocument=FreeCAD.getDocument(doc.Label)
+ # FreeCADGui.ActiveDocument=FreeCADGui.getDocument(doc.Label)
+ if close_doc:
FreeCAD.closeDocument(doc.Name)
say(doc.Label)
+
+
##
def tabify():
- #global KSUWidget
+ # global KSUWidget
- KSUWidget.setFloating(False) #dock
- KSUWidget.resize(sizeX,sizeY)
+ KSUWidget.setFloating(False) # dock
+ KSUWidget.resize(sizeX, sizeY)
KSUWidget.activateWindow()
KSUWidget.raise_()
- t=FreeCADGui.getMainWindow()
+ t = FreeCADGui.getMainWindow()
cv = t.findChild(QtGui.QDockWidget, "Combo View")
if cv is None:
cv = t.findChild(QtGui.QDockWidget, "ComboView")
@@ -1377,574 +1470,564 @@ def tabify():
if cv is None:
cv = t.findChild(QtGui.QDockWidget, "Tree view")
if cv is None:
- cv = [o for o in t.children () if o.objectName () == "Combo View"]
- if cv:
- cv = cv[0]
- else:
- cv = None
+ cv = [o for o in t.children() if o.objectName() == "Combo View"]
+ cv = cv[0] if cv else None
if KSUWidget and cv:
- dw=t.findChildren(QtGui.QDockWidget)
- try:
- t.tabifyDockWidget(cv,KSUWidget)
- except:
- pass
- k_tab = t.findChild(QtGui.QDockWidget, "kicadStepUp") #"kicad StepUp 3D tools")
+ t.findChildren(QtGui.QDockWidget)
+ with contextlib.suppress(BaseException):
+ t.tabifyDockWidget(cv, KSUWidget)
+ k_tab = t.findChild(QtGui.QDockWidget, "kicadStepUp") # "kicad StepUp 3D tools")
k_tab.activateWindow()
k_tab.raise_()
KSUWidget.showMaximized()
KSUWidget.activateWindow()
KSUWidget.raise_()
- say( "Tabified done !")
- ksu_tab = t.findChild(QtGui.QDockWidget, "kicadStepUp") #"kicad StepUp 3D tools")
+ say("Tabified done !")
+ ksu_tab = t.findChild(QtGui.QDockWidget, "kicadStepUp") # "kicad StepUp 3D tools")
if ksu_tab:
- #say ("ksu tab ->"+ksu_tab.objectName())
- KSUWidget.resize(sizeX,sizeY)
+ # say ("ksu tab ->"+ksu_tab.objectName())
+ KSUWidget.resize(sizeX, sizeY)
ksu_tab.activateWindow()
ksu_tab.raise_()
- #say ("focus on me!")
-
+ # say ("focus on me!")
+
+
def dock():
global expanded_view, mingui
- expanded_view=0; mingui=0
- #KSUmw = FreeCADGui.getMainWindow() # PySide # the active qt window, = the freecad window since we are inside it
- #KSUmw.addDockWidget(QtCore.Qt.LeftDockWidgetArea,KSUWidget) # add the widget to the main window
- textEdit_dim=textEdit_dim_hide
- KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
- KSUWidget.ui.textEdit.Visible=False
- KSUWidget.setFloating(False) #dock
- KSUWidget.resize(sizeX,sizeY)
+ expanded_view = 0
+ mingui = 0
+ # KSUmw = FreeCADGui.getMainWindow() # PySide # the active qt window, = the freecad window since we are inside it
+ # KSUmw.addDockWidget(QtCore.Qt.LeftDockWidgetArea,KSUWidget) # add the widget to the main window
+ textEdit_dim = textEdit_dim_hide
+ KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0], textEdit_dim[1], textEdit_dim[2], textEdit_dim[3])
+ KSUWidget.ui.textEdit.Visible = False
+ KSUWidget.setFloating(False) # dock
+ KSUWidget.resize(sizeX, sizeY)
KSUWidget.activateWindow()
KSUWidget.raise_()
- #KSUWidget.ui.HelpPB.clicked.connect(KSUWidget.ui.onHelp)
+ # KSUWidget.ui.HelpPB.clicked.connect(KSUWidget.ui.onHelp)
cfg_read_all()
- ini_vars[16] = u'left'
- docking_mode='left'
- #cfg_update_all()
+ ini_vars[16] = "left"
+ # cfg_update_all()
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- dock_mode = pg.SetInt("dockingMode", 1)
+ pg.SetInt("dockingMode", 1)
tabify()
- #KSUWidget.setFloating(False) #dock
- #say ("now!")
+ # KSUWidget.setFloating(False) #dock
+ # say ("now!")
+
+
##
def dock_right():
global expanded_view, mingui
- expanded_view=0;mingui=0
- KSUmw = FreeCADGui.getMainWindow() # PySide # the active qt window, = the freecad window since we are inside it
- t=FreeCADGui.getMainWindow()
- dw=t.findChildren(QtGui.QDockWidget)
- looping=False
- ldw=len (dw)
- if ldw>0:
- looping=True
- idw=0
- cv=None
+ expanded_view = 0
+ mingui = 0
+ KSUmw = FreeCADGui.getMainWindow() # PySide # the active qt window, = the freecad window since we are inside it
+ t = FreeCADGui.getMainWindow()
+ dw = t.findChildren(QtGui.QDockWidget)
+ looping = False
+ ldw = len(dw)
+ if ldw > 0:
+ looping = True
+ idw = 0
+ cv = None
while looping and idw < ldw:
- #for d in dw:
- d=dw[idw]
- idw+=1
+ # for d in dw:
+ d = dw[idw]
+ idw += 1
area = t.dockWidgetArea(d)
- #if area == QtCore.Qt.LeftDockWidgetArea:
+ # if area == QtCore.Qt.LeftDockWidgetArea:
# print (d.windowTitle(), '(Left)')
if area == QtCore.Qt.RightDockWidgetArea:
- print (d.windowTitle(), '(Right)')
- r_w=str(d.objectName()) #;print(r_w)
+ print(d.windowTitle(), "(Right)")
+ r_w = str(d.objectName()) # ;print(r_w)
cv = t.findChild(QtGui.QDockWidget, r_w)
- looping=False
- KSUmw.addDockWidget(QtCore.Qt.RightDockWidgetArea,KSUWidget)
- KSUWidget.setFloating(False) #dock
- #RHDockWidget.resize(sizeXright,sizeYright)
+ looping = False
+ KSUmw.addDockWidget(QtCore.Qt.RightDockWidgetArea, KSUWidget)
+ KSUWidget.setFloating(False) # dock
+ # RHDockWidget.resize(sizeXright,sizeYright)
KSUWidget.activateWindow()
KSUWidget.raise_()
if KSUWidget and cv is not None:
- dw=t.findChildren(QtGui.QDockWidget)
- #t.tabifyDockWidget(cv,RHDockWidget)
+ dw = t.findChildren(QtGui.QDockWidget)
+ # t.tabifyDockWidget(cv,RHDockWidget)
try:
- t.tabifyDockWidget(cv,KSUWidget)
- say( "Tabified done !")
- #stop
+ t.tabifyDockWidget(cv, KSUWidget)
+ say("Tabified done !")
+ # stop
except:
- say('exception raised')
- pass
- #KSUmw = FreeCADGui.getMainWindow() # PySide # the active qt window, = the freecad window since we are inside it
- #KSUmw.addDockWidget(QtCore.Qt.RightDockWidgetArea,KSUWidget) # add the widget to the main window
- textEdit_dim=textEdit_dim_hide
- KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
- KSUWidget.ui.textEdit.Visible=False
- KSUWidget.setFloating(False) #dock
- KSUWidget.resize(sizeXright,sizeYright)
+ say("exception raised")
+ # KSUmw = FreeCADGui.getMainWindow() # PySide # the active qt window, = the freecad window since we are inside it
+ # KSUmw.addDockWidget(QtCore.Qt.RightDockWidgetArea,KSUWidget) # add the widget to the main window
+ textEdit_dim = textEdit_dim_hide
+ KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0], textEdit_dim[1], textEdit_dim[2], textEdit_dim[3])
+ KSUWidget.ui.textEdit.Visible = False
+ KSUWidget.setFloating(False) # dock
+ KSUWidget.resize(sizeXright, sizeYright)
KSUWidget.activateWindow()
KSUWidget.raise_()
cfg_read_all()
- ini_vars[16] = u'right'
- docking_mode='right'
- #cfg_update_all()
+ ini_vars[16] = "right"
+ # cfg_update_all()
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- dock_mode = pg.SetInt("dockingMode", 2)
- #KSUWidget.setFloating(False) #dock
- #say ("now!")
+ pg.SetInt("dockingMode", 2)
+ # KSUWidget.setFloating(False) #dock
+ # say ("now!")
+
+
##
def undock():
global expanded_view, mingui
- expanded_view=0; mingui=0
- textEdit_dim=textEdit_dim_base
- KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
- KSUWidget.ui.textEdit.Visible=True
- KSUWidget.setFloating(True) #undock
- KSUWidget.resize(sizeX,sizeY)
+ expanded_view = 0
+ mingui = 0
+ textEdit_dim = textEdit_dim_base
+ KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0], textEdit_dim[1], textEdit_dim[2], textEdit_dim[3])
+ KSUWidget.ui.textEdit.Visible = True
+ KSUWidget.setFloating(True) # undock
+ KSUWidget.resize(sizeX, sizeY)
KSUWidget.activateWindow()
KSUWidget.raise_()
cfg_read_all()
- ini_vars[16] = u'float'
- docking_mode='float'
- #cfg_update_all()
+ ini_vars[16] = "float"
+ # cfg_update_all()
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- dock_mode = pg.SetInt("dockingMode", 0)
- #KSUWidget.resize(QtCore.QSize(300,100).expandedTo(KSUWidget.maximumSize())) # sets size of the widget
- #KSUWidget.setFloating(False) #dock
- #say ("now!")
+ pg.SetInt("dockingMode", 0)
+ # KSUWidget.resize(QtCore.QSize(300,100).expandedTo(KSUWidget.maximumSize())) # sets size of the widget
+ # KSUWidget.setFloating(False) #dock
+ # say ("now!")
+
+
##
def temporary_undock():
global expanded_view, mingui
- mingui=0
- #expanded_view=0
- #tabify()
- textEdit_dim=textEdit_dim_base
- KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
- KSUWidget.setFloating(True) #undock
- KSUWidget.resize(sizeX,sizeY)
+ mingui = 0
+ # expanded_view=0
+ # tabify()
+ textEdit_dim = textEdit_dim_base
+ KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0], textEdit_dim[1], textEdit_dim[2], textEdit_dim[3])
+ KSUWidget.setFloating(True) # undock
+ KSUWidget.resize(sizeX, sizeY)
KSUWidget.activateWindow()
KSUWidget.raise_()
- #KSUWidget.resize(QtCore.QSize(300,100).expandedTo(KSUWidget.maximumSize())) # sets size of the widget
- #KSUWidget.setFloating(False) #dock
- #say ("now!")
+ # KSUWidget.resize(QtCore.QSize(300,100).expandedTo(KSUWidget.maximumSize())) # sets size of the widget
+ # KSUWidget.setFloating(False) #dock
+ # say ("now!")
+
+
##
def minimz():
- #clear_console()
+ # clear_console()
global mingui
-
- #sayerr(mingui)
- if mingui==0:
- KSUWidget.setFloating(True) #undock
- # KSUWidget.hide();
+
+ # sayerr(mingui)
+ if mingui == 0:
+ KSUWidget.setFloating(True) # undock
+ # KSUWidget.hide();
# KSUWidget.setWindowState(QtCore.Qt.WindowMinimized)
- #KSUWidget.resize(500, 500)
- KSUWidget.resize(sizeXmin,sizeYmin)
+ # KSUWidget.resize(500, 500)
+ KSUWidget.resize(sizeXmin, sizeYmin)
KSUWidget.activateWindow()
KSUWidget.raise_()
- mingui=1
+ mingui = 1
else:
- mingui=0
+ mingui = 0
cfg_read_all()
- if docking_mode == 'float':
+ if docking_mode == "float":
undock()
- KSUWidget.setVisibility=True
- elif docking_mode == 'left':
- #tabify()
+ KSUWidget.setVisibility = True
+ elif docking_mode == "left":
+ # tabify()
dock()
- KSUWidget.setVisibility=True
+ KSUWidget.setVisibility = True
else:
dock_right()
- KSUWidget.setVisibility=True
- #sayw(mingui)
-
- #sayw("kicad StepUp version "+str(___ver___))
+ KSUWidget.setVisibility = True
+ # sayw(mingui)
+
+ # sayw("kicad StepUp version "+str(___ver___))
+
+
##
def minimz_alt():
- KSUWidget.setFloating(True) #undock
+ KSUWidget.setFloating(True) # undock
KSUWidget.setWindowState(QtCore.Qt.WindowMinimized)
- KSUWidget.resize(sizeX,sizeY)
+ KSUWidget.resize(sizeX, sizeY)
KSUWidget.activateWindow()
- #KSUWidget.raise_()
+ # KSUWidget.raise_()
+
+
##
def onDestroy():
- say ("Do stuff here")
-##
-#font_size=12
+ say("Do stuff here")
+
+
+##
+# font_size=12
####################################
# embedded button images
import base64
+
# "b64_data" is a variable containing your base64 encoded jpeg
-axis_b64 =\
-"""
+axis_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB3aWR0aD0iNjRweCIKICAgaGVpZ2h0PSI2NHB4IgogICBpZD0ic3ZnODI3NyIKICAgdmVyc2lvbj0iMS4xIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkyLjAgcjE1Mjk5IgogICBzb2RpcG9kaTpkb2NuYW1lPSJBeGlzLnN2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczgyNzkiIC8+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjcuNzc4MTc0NiIKICAgICBpbmtzY2FwZTpjeD0iOS4wMTQ4ODU4IgogICAgIGlua3NjYXBlOmN5PSIzMy4zNDUxNzgiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNTM2IgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjgwMSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6c25hcC1nbG9iYWw9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9ImZhbHNlIj4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDU2MjUiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhODI4MiI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGU+PC9kYzp0aXRsZT4KICAgICAgICA8ZGM6dGl0bGU+UGF0aC1BeGlzPC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDE1LTA3LTA0PC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL1BhdGgvR3VpL1Jlc291cmNlcy9pY29ucy9QYXRoLUF4aXMuc3ZnPC9kYzppZGVudGlmaWVyPgogICAgICAgIDxkYzpyaWdodHM+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEIExHUEwyKzwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cmlnaHRzPgogICAgICAgIDxjYzpsaWNlbnNlPmh0dHBzOi8vd3d3LmdudS5vcmcvY29weWxlZnQvbGVzc2VyLmh0bWw8L2NjOmxpY2Vuc2U+CiAgICAgICAgPGRjOmNvbnRyaWJ1dG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2Fncnlzb25dIEFsZXhhbmRlciBHcnlzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8ZwogICAgICAgaWQ9Imc2ODQ2IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4wNjE5MTI2LDAsMCwxLjA2MTkxMjYsMy44NzYxNzM1LC0zLjgzNDE4NDMpIj4KICAgICAgPHBhdGgKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJzc3NzcyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg2NTE0IgogICAgICAgICBkPSJtIDQ2LDIwLjg0NDgxMSBjIDEuODg2NjU2LDIuODU0OTU4IDEsNy40NTc1MjkgLTEsOC4zODk3MiAtMiwwLjkzMjE5MSAtNC4xMTMzNDQsMC44NzE0ODUgLTYsLTEuOTgzNDc0IC0xLjg4NjY1NSwtMi44NTQ5NTkgLTIuNTU3NDk3LC02LjUxMTExMiAtMSwtOC4yNzA2MjkgMS41NTc0OTcsLTEuNzU5NTE3IDYuMTEzMzQ0LC0wLjk5MDU3NiA4LDEuODY0MzgzIHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiM4YWUyMzQ7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMxNzJhMDQ7c3Ryb2tlLXdpZHRoOjIuMDAwMDAwMjQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjMyLjIwMDAwMDc2O3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNjQxOSIKICAgICAgICAgZD0ibSAxMCwxOC45ODA0MjkgNCwyMC41MDgyMDUiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNjQxOS02IgogICAgICAgICBkPSJtIDEwLDE4Ljk4MDQyOSA0LDIwLjUwODIwNSIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzM0NjVhNDtzdHJva2Utd2lkdGg6NDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg2NDE5LTYtMiIKICAgICAgICAgZD0ibSA5LDE4Ljk4MDQyOSA0LDIwLjUwODIwNSIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDY0NzUtMy01IgogICAgICAgICBkPSJtIDQ2LDI4LjMwMjMzOSBjIDIsLTIuNzk2NTczIDAsLTEwLjI1NDEwMiAtNiwtMTAuMjU0MTAyIGwgMTIsMWUtNiB6IgogICAgICAgICBzdHlsZT0iZmlsbDojNzNkMjE2O3N0cm9rZTojMTcyYTA0O3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDozMi4yMDAwMDA3NjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDY1NzEiCiAgICAgICAgIGQ9Im0gNDQsMTkuOTEyNjIgNi45NTQ1NDYsLTAuMDIxMTkiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM4YWUyMzQ7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDY0NzUtMy01LTEiCiAgICAgICAgIGQ9Im0gNDUuOTc3MjczLDI4LjMyMzUyNiBjIDIsLTIuNzk2NTc0IDAsLTEwLjI1NDEwMyAtNiwtMTAuMjU0MTAzIGwgMTIsMWUtNiB6IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMTcyYTA0O3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDozMi4yMDAwMDA3NjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDYzOTctMyIKICAgICAgICAgZD0iTSAxNCwzOS40ODg2MzQgNDAsMjQuNTczNTc2IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMTcyYTA0O3N0cm9rZS13aWR0aDo4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDYzOTctMy03IgogICAgICAgICBkPSJNIDE0LDM5LjQ4ODYzNCA0MCwyNC41NzM1NzYiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3M2QyMTY7c3Ryb2tlLXdpZHRoOjQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNjM5Ny0zLTctNyIKICAgICAgICAgZD0ibSAxMy41OTA5MDksMzguNTk4ODE2IDI2LC0xNC45MTUwNTkiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM4YWUyMzQ7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNjM5NyIKICAgICAgICAgZD0iTSAxNCwzOS40ODg2MzQgMzIsNTQuNDAzNjkyIgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMjgwMDAwO3N0cm9rZS13aWR0aDo4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDYzOTctNSIKICAgICAgICAgZD0iTSAxNCwzOS40ODg2MzQgMzIsNTQuNDAzNjkyIgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojY2MwMDAwO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDYzOTctNS0wIgogICAgICAgICBkPSJtIDEzLjE2MDcwNiw0MC4wNjEyODQgMTgsMTQuOTE1MDU4IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2MiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNjQ3NSIKICAgICAgICAgZD0iTSAxNiwxNS4yNTE2NjQgQyAxMy45MzI1NTQsMTkuMDI0NzEyIDYsMTkuOTEyNjIgMywxOC4wNDgyMzggTCA3LDYuODYxOTQzOCBaIgogICAgICAgICBzdHlsZT0iZmlsbDojMzQ2NWE0O3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDozMi4yMDAwMDA3NjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2MiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNjQ3NS02IgogICAgICAgICBkPSJNIDEzLjMyMTQxMiwxNS4zNzE1MTEgQyAxMS45NjY1OCwxNi42OTI4MjQgOC4wMDc5ODYsMTcuNDc1MTcyIDUuNTAwNzA5NiwxNi45MTAwNDYgTCA3LjgwNzE1MjcsMTAuMjkxMDkxIFoiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjMyLjIwMDAwMDc2O3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjYyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg2NDc1LTMiCiAgICAgICAgIGQ9Im0gMjYuNzA1NzcxLDU3Ljg1ODE4IGMgLTAuMjMzMjkxLC00LjIzMTE4MiA2LjE2MDI1NCwtOC42OTc0NjIgOS43NTgzMzEsLTguNDgxMTQ3IEwgMzksNjAuOTI5MDMxIFoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNjYzAwMDA7c3Ryb2tlOiMyODAwMDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjMyLjIwMDAwMDc2O3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjYyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg2NDc1LTYtMiIKICAgICAgICAgZD0ibSAyOC45MzYyNDcsNTYuNTA2NDc0IGMgMC40NjI5MzcsLTEuNzc2MTQ5IDMuNDY5MTgsLTQuMzAxMjIyIDUuOTQzMDI0LC00Ljk4MjQ1OSBsIDEuNTU5MTY4LDYuODA1OTM3IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNlZjI5Mjk7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjMyLjIwMDAwMDc2O3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICA8L2c+CiAgICA8ZwogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTAuMTM3NDgyNDgsLTAuNDQxODAxMTYsMC40NDE4MDExNiwtMC4xMzc0ODI0OCwzOC4yMTMwNSw1OC43NjkwMjYpIgogICAgICAgaWQ9Imc2ODQ2LTgiIC8+CiAgPC9nPgo8L3N2Zz4K
-"""
-exportBoard_b64=\
"""
+exportBoard_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY4LjI2NjY3IgogICBoZWlnaHQ9IjY4LjI2NjY3IgogICBpZD0ic3ZnMjg2MCIKICAgc29kaXBvZGk6dmVyc2lvbj0iMC4zMiIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45Mi4wIHIxNTI5OSIKICAgc29kaXBvZGk6ZG9jbmFtZT0iZXhwb3J0UGFydF91cGRhdGUuc3ZnIgogICBpbmtzY2FwZTpvdXRwdXRfZXh0ZW5zaW9uPSJvcmcuaW5rc2NhcGUub3V0cHV0LnN2Zy5pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgNjQgNjQiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMyODYyIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzk0NSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM4YWUyMzQ7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzOTQ3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzNkMjE2O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzk0OSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQzODciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQzODkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDM5MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzNzciCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzNjkyIgogICAgICAgY3g9IjQ1Ljg4MzMyNyIKICAgICAgIGN5PSIyOC44Njk1NjgiCiAgICAgICBmeD0iNDUuODgzMzI3IgogICAgICAgZnk9IjI4Ljg2OTU2OCIKICAgICAgIHI9IjE5LjQ2NzQzNiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgtMC4yMzQ0MzIyNCwwLjIzNDQzMTk4KSIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDM4NyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM3MDMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN4PSIxMzEuNDgxODciCiAgICAgICBjeT0iOTMuNTU3Mjg5IgogICAgICAgZng9IjEzMS40ODE4NyIKICAgICAgIGZ5PSI5My41NTcyODkiCiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNTI3MTEwNjQsMS44MTU4ODc0LC0xLjQ1MzQ4NDMsMC40MjE5MTMzMSwyMDMuMjM0MDUsLTE4Ny42NTgzKSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzM3NyI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzM3OSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmFmZjJiO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMzgxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmFhMDA7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDM4NyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM3MDUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN4PSIxNDcuMDU3MTMiCiAgICAgICBjeT0iODMuOTg5MTQzIgogICAgICAgZng9IjE0Ny4wNTcxMyIKICAgICAgIGZ5PSI4My45ODkxNDMiCiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMjk2NjAyOCwwLjE3NzExMjMxLC0wLjE0MDkyODYxLDEuMDMxNzA5NCwtMzIuNjg5OTI5LC0yOS4xMDkyNzQpIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDMxLjk5OTk5OCA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogOTk5Ljk5OTk1IDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjYzLjk5OTk5NyA6IDMxLjk5OTk5OCA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzEuOTk5OTk4IDogMjEuMzMzMzMyIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI4NjgiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzNzctMyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM2OTItNSIKICAgICAgIGN4PSI0NS44ODMzMjciCiAgICAgICBjeT0iMjguODY5NTY4IgogICAgICAgZng9IjQ1Ljg4MzMyNyIKICAgICAgIGZ5PSIyOC44Njk1NjgiCiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTAuMjM0NDMyMjQsMC4yMzQ0MzE5OCkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMzNzctMyI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzM3OS04IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmYWZmMmI7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMzODEtMyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZhYTAwO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtNCkiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzNzY3IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc3MyIKICAgICAgIHgxPSIyMi4xMTY1MTYiCiAgICAgICB5MT0iNTUuNzE3NTE4IgogICAgICAgeDI9IjE3LjMyODU0NyIKICAgICAgIHkyPSIyMS4zMTEzNCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzY3Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM0NjVhNDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM3NjkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNzcxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgwLC00KSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM3NzciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzgzIgogICAgICAgeDE9IjUzLjg5Njc2MyIKICAgICAgIHkxPSI1MS4xNzk3ODciCiAgICAgICB4Mj0iNDcuNTAyMjM1IgogICAgICAgeTI9IjIxLjgzNzQyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NzciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzc3OSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM0NjVhNDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM3ODEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ4NjYyIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50Mzc1NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwwLjUzNjcyMywwLDE2Ljg3MzA2KSIKICAgICAgIGN4PSIyNC44MzcxMjYiCiAgICAgICBjeT0iMzYuNDIxMTI3IgogICAgICAgZng9IjI0LjgzNzEyNiIKICAgICAgIGZ5PSIzNi40MjExMjciCiAgICAgICByPSIxNS42NDQ3MzciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDg2NjIiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDg2NjQiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wODY2NiIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAwMDAwO3N0b3Atb3BhY2l0eTowOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI4NDciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzU5IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKC02NC4yNDc4MTEsNS41ODI1MTM4KSIKICAgICAgIHgxPSIzMi42NDc5NzIiCiAgICAgICB5MT0iMzAuNzQ4ODQ2IgogICAgICAgeDI9IjM3LjEyNDQ2MiIKICAgICAgIHkyPSIyNC44NDIyNTMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI2ODIiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzYxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKC02NC4yNDc4MTEsNS41ODI1MTM4KSIKICAgICAgIHgxPSIzNi43MTM4MzciCiAgICAgICB5MT0iMzEuNDU1OTUyIgogICAgICAgeDI9IjM3LjEyNDQ2MiIKICAgICAgIHkyPSIyNC44NDIyNTMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDI2ODIiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDI2ODQiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzRlOWEwNjtzdG9wLW9wYWNpdHk6MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyNjg2IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM4OWFlZGM7c3RvcC1vcGFjaXR5OjA7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MjQwMiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NjctMyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjE4LjkzNTc2NiIKICAgICAgIHkxPSIyMy42Njc4OTYiCiAgICAgICB4Mj0iNTMuNTg4NjIzIgogICAgICAgeTI9IjI2LjY0OTM2MyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MjQwMiI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMjQwNCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyNDA2IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM1MjhhYzU7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mjg3MSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NjkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSI0Ni44MzQ4MTYiCiAgICAgICB5MT0iNDUuMjY0MTIyIgogICAgICAgeDI9IjQ1LjM4MDQzNiIKICAgICAgIHkyPSI1MC45Mzk2NjciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDI4NzEiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDI4NzMiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM0NjVhNDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMjg3NSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzQ2NWE0O3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzk0NSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NjMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSIxOC45MzU3NjYiCiAgICAgICB5MT0iMjMuNjY3ODk2IgogICAgICAgeDI9IjUzLjU4ODYyMyIKICAgICAgIHkyPSIyNi42NDkzNjMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNDkiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMxNTEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzE1MyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNTI4YWM1O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI3OTciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzcxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iNS45NjQ5MTc3IgogICAgICAgeTE9IjI2LjA0ODE2NCIKICAgICAgIHgyPSI1Mi44NTQwOTUiCiAgICAgICB5Mj0iMjYuMDQ4MTY0IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyNzk3IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyNzk5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDI4MDEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MDsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyODQ3IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc0NSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgtNjMuNzgyMzk4LDUuMzA0OTIwOCkiCiAgICAgICB4MT0iMTMuNDc4NTU0IgogICAgICAgeTE9IjEwLjYxMjIwNiIKICAgICAgIHgyPSIxNS40MTk0MTciCiAgICAgICB5Mj0iMTkuMTE1MTIyIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyODMxIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyODMzIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMzNDY1YTQ7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNWI4NmJlO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwLjMzMzMzMzM0IgogICAgICAgICBpZD0ic3RvcDI4NTUiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMjgzNSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojODNhOGQ4O3N0b3Atb3BhY2l0eTowOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI4NDciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzQ3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0icm90YXRlKDE4MCwtOC4zNTk5NTA1LDI1LjcxNDk2MikiCiAgICAgICB4MT0iMzcuMTI4MDUyIgogICAgICAgeTE9IjI5LjcyOTYwNSIKICAgICAgIHgyPSIzNy4wNjU0MTQiCiAgICAgICB5Mj0iMjYuMTk0MDcxIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyODQ3IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyODQ5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM0ZTlhMDY7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMjg1MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzQ2NWE0O3N0b3Atb3BhY2l0eTowOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDIzODAiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzUzIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iNjIuNTEzODM2IgogICAgICAgeTE9IjM2LjA2MTIzNyIKICAgICAgIHgyPSIxNS45ODQ4NjMiCiAgICAgICB5Mj0iMjAuNjA4NTgiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDIzODAiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDIzODIiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2I5Y2ZlNztzdG9wLW9wYWNpdHk6MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyMzg0IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzOTQ1IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc0OSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjYyLjUxMzgzNiIKICAgICAgIHkxPSIzNi4wNjEyMzciCiAgICAgICB4Mj0iMTUuOTg0ODYzIgogICAgICAgeTI9IjIwLjYwODU4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTgwIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMTgyIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNiOWNmZTc7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzE4NCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mjc5NyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NTUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSI1Ljk2NDkxNzciCiAgICAgICB5MT0iMjYuMDQ4MTY0IgogICAgICAgeDI9IjUyLjg1NDA5NSIKICAgICAgIHkyPSIyNi4wNDgxNjQiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDg2NjIiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzOTY4IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMTMxNDQ2NSwwLDAsMS40NzAxNDI1LDExLjkxMjI4NywtNjkuNzYzNTYpIgogICAgICAgY3g9IjI0LjgzNzEyNiIKICAgICAgIGN5PSIzNi40MjExMjciCiAgICAgICBmeD0iMjQuODM3MTI2IgogICAgICAgZnk9IjM2LjQyMTEyNyIKICAgICAgIHI9IjE1LjY0NDczNyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mjg0NyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5NzAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC43NTk0OTQ2MSwwLDAsMC43NTk0OTQ2MSwtNTguMzk5OTI2LC0wLjE3NjMwODg2KSIKICAgICAgIHgxPSIzMi42NDc5NzIiCiAgICAgICB5MT0iMzAuNzQ4ODQ2IgogICAgICAgeDI9IjM3LjEyNDQ2MiIKICAgICAgIHkyPSIyNC44NDIyNTMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI2ODIiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTcyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNzU5NDk0NjEsMCwwLDAuNzU5NDk0NjEsLTU4LjM5OTkyNiwtMC4xNzYzMDg4NikiCiAgICAgICB4MT0iMzYuNzEzODM3IgogICAgICAgeTE9IjMxLjQ1NTk1MiIKICAgICAgIHgyPSIzNy4xMjQ0NjIiCiAgICAgICB5Mj0iMjQuODQyMjUzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzOTE2IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzk2MyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgwMDAwMDA3LDAsMCwwLjc4NDMxMzY4LDAuMjAwMDAwODIsLTMwLjA5ODAzOCkiCiAgICAgICB4MT0iMzcuMjQ5OTk2IgogICAgICAgeTE9IjI1LjA5MjM0MiIKICAgICAgIHgyPSIzOS43NDk5OTYiCiAgICAgICB5Mj0iNDAuOTI0OTk5IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTE2Ij4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzOTE4IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM4YWUyMzQ7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzkyMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNGU5YTA2O3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjkuMDgyMDMwOCIKICAgICBpbmtzY2FwZTpjeD0iMzQuMTMzMzM1IgogICAgIGlua3NjYXBlOmN5PSIzNC4xMzMzMzUiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzM5NTEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDAxIgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIgogICAgICAgb3JpZ2lueD0iMCIKICAgICAgIG9yaWdpbnk9IjAiCiAgICAgICBzcGFjaW5neD0iMSIKICAgICAgIHNwYWNpbmd5PSIxIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTI4NjUiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bU3RlZmFuIFRyw7ZnZXJdPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjcmVhdG9yPgogICAgICAgIDxkYzp0aXRsZT5mZW0tYm94PC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDE1LTExLTE1PC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kLzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8Y2M6bGljZW5zZT5odHRwczovL3d3dy5nbnUub3JnL2NvcHlsZWZ0L2xlc3Nlci5odG1sPC9jYzpsaWNlbnNlPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOiM3MjlmY2Y7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gMywxMyAzNywxOSA2MSwxMSAzMSw3IFoiCiAgICAgICBpZD0icGF0aDI5OTMiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50Mzc4Myk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gNjEsMTEgViA0NyBMIDM3LDU3IFYgMTkgWiIKICAgICAgIGlkPSJwYXRoMjk5NSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiCiAgICAgICBpZD0icGF0aDM4MjUiCiAgICAgICBkPSJtIDMsMTMgMzQsNiBWIDU3IEwgMyw1MSBaIgogICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM3NzMpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gNSwxNS40Mjc3MiAwLjAwODY3LDMzLjkxOTExNiAzMC4wMDg2NzEsNS4yNjg3OTkgLTAuMDA4NywtMzMuOTMzNjE0IHoiCiAgICAgICBpZD0icGF0aDM3NjUiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMzQ2NWE0O3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJtIDM5LjAxMjQzLDIwLjQzMzgzMyAtMC4wMTIyNiwzMy41MzUzMDEgMjAuMDAxMTA1LC04LjMwMDk5MyAzLjZlLTQsLTMxLjg2NzM2MyB6IgogICAgICAgaWQ9InBhdGgzNzc1IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICA8ZwogICAgICAgaWQ9ImczOTUxIgogICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNzMuMjQ0MTQ5LDEyLjI4MDcxNykiPgogICAgICA8ZWxsaXBzZQogICAgICAgICByeT0iMjMuMDAwMDAyIgogICAgICAgICByeD0iMTcuNzAxMTgzIgogICAgICAgICBjeT0iLTE2LjIxOTI4NCIKICAgICAgICAgY3g9IjQwLjAxNDE2OCIKICAgICAgICAgaW5rc2NhcGU6cl9jeT0idHJ1ZSIKICAgICAgICAgaW5rc2NhcGU6cl9jeD0idHJ1ZSIKICAgICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTt2aXNpYmlsaXR5OnZpc2libGU7b3BhY2l0eTowLjM4MzMzMzMzO2ZpbGw6dXJsKCNyYWRpYWxHcmFkaWVudDM5NjgpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjkxNTc3MTAxO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO21hcmtlcjpub25lIgogICAgICAgICBpZD0icGF0aDg2NjAiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoLTEpIiAvPgogICAgICA8cGF0aAogICAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmJsb2NrO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM5NzApO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTp1cmwoI2xpbmVhckdyYWRpZW50Mzk3Mik7c3Ryb2tlLXdpZHRoOjAuNzU4MDAwMDI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlcjpub25lIgogICAgICAgICBkPSJtIC0zNi44NDkyNjcsMjUuMjE5MjkyIGMgMCwwIDYuNzg3OTgzLDAuNDc0Njg0IDQuNjk5MzczLC03LjUwMDAwOSBoIDUuOTA1NzQ1IGMgMCwxLjE0MTIxOCAtMC40NDY4NzcsOS4wMTg5OTkgLTEwLjYwNTExOCw3LjUwMDAwOSB6IgogICAgICAgICBpZD0icGF0aDI4MzkiCiAgICAgICAgIGlua3NjYXBlOnJfY3g9InRydWUiCiAgICAgICAgIGlua3NjYXBlOnJfY3k9InRydWUiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjYyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgPGcKICAgICAgICAgaWQ9ImcxNjk2IgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjE0Mzg0ODgsMCwwLDEuMTQzODQ4OCwxLjUyMDAzNTQsLTQuMzk0NjExNykiPgogICAgICAgIDxnCiAgICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO3N0cm9rZS13aWR0aDoxLjMyOTA3MTQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgICAgaWQ9ImczOTU5IgogICAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuOTM3NDk5OTQsMCwwLDAuOTM3NDk5OTQsLTU2LjUwNDM5MywyNS44NjI3MTMpIj4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgICAgICBpZD0icGF0aDMzNDMtMCIKICAgICAgICAgICAgIGQ9Im0gMzUsLTEzIHYgNCBjIC0xMCwwIC0xNywyIC0yMyw3IGwgNSw3IGMgNS41MzMxMDcsLTMuMjk2OTI0MyAxMS4zMDQ3MDMsLTUuOTMxMzgxMzcgMTgsLTYgdiA0IGwgMTQsLTggeiIKICAgICAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzOTYzKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzE3MmEwNDtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgICAgICBpZD0icGF0aDMzNDMtMi05IgogICAgICAgICAgICAgZD0ibSAzNywtOS41ODIyMzA0IC0wLjAzNDUzLDIuNDk1OTEzNyBDIDI0LC03IDIwLC01IDE0Ljc0MjMyNCwtMS42MjE0ODA1IGwgMi44MjM4OTcsMy45NzQ2MTY5IEMgMjAuMjI0NDI0LDAuOTEzNjgzMjUgMjYsLTMgMzcsLTMgdiAyLjU4MjIzMDQgTCA0NSwtNSBaIgogICAgICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO2ZpbGw6bm9uZTtzdHJva2U6IzhhZTIzNDtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgICA8L2c+CiAgICAgIDwvZz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=
"""
-importBoard_b64=\
-"""
+importBoard_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIGhlaWdodD0iNjQiCiAgIHdpZHRoPSI2NCIKICAgdmVyc2lvbj0iMS4xIgogICBpZD0ic3ZnMiIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45Mi4wIHIxNTI5OSIKICAgc29kaXBvZGk6ZG9jbmFtZT0iaW1wb3J0Qm9hcmQuc3ZnIj4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEyOCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGUgLz4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxIgogICAgIG9iamVjdHRvbGVyYW5jZT0iMTAiCiAgICAgZ3JpZHRvbGVyYW5jZT0iMTAiCiAgICAgZ3VpZGV0b2xlcmFuY2U9IjEwIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNTM2IgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjgwMSIKICAgICBpZD0ibmFtZWR2aWV3MjYiCiAgICAgc2hvd2dyaWQ9ImZhbHNlIgogICAgIGlua3NjYXBlOnpvb209IjcuMzc1IgogICAgIGlua3NjYXBlOmN4PSIxNS4zODU2MjgiCiAgICAgaW5rc2NhcGU6Y3k9IjIxLjk2Njk0MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMiIgLz4KICA8ZGVmcwogICAgIGlkPSJkZWZzNCI+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIHgxPSI4MS44OTgwMDMiCiAgICAgICB5MT0iMTcuNzI5IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjczODczLDAsMCwxLjM1MzcsMCwyLjAwMDA5MTcpIgogICAgICAgeDI9IjMuMDQ1OCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeTI9IjE3LjcyOSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NjYiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4NjgiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3RvcC1jb2xvcj0iI2NjODAwMCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODcwIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0b3AtY29sb3I9IiNmZmVkMDAiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0iYyIKICAgICAgIHkyPSIxNy43MjkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgyPSIzLjA0NTgiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNzM4NzMsMCwwLDEuMzUzNywwLDIuMDAwMDkxNykiCiAgICAgICB5MT0iMTcuNzI5IgogICAgICAgeDE9IjgxLjg5OCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNjYzgwMDAiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZmZlZDAwIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wOSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJkIgogICAgICAgeTI9IjEuODQ2OCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDI9IjQ4LjI2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjAwMDAxODgsMCwwLDEuMDAwMDE4OCwwLDIuMDAwMDkxNykiCiAgICAgICB5MT0iMzMuNjEyIgogICAgICAgeDE9IjM0LjI5Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2FmN2QwMCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDEyIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZmZlZDAwIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMTQiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjZCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDI5OTMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4wMDAwMTg4LDAsMCwxLjAwMDAxODgsMCwxMC4wMDAwOTIpIgogICAgICAgeDE9IjM0LjI5IgogICAgICAgeTE9IjMzLjYxMiIKICAgICAgIHgyPSI0OC4yNiIKICAgICAgIHkyPSIxLjg0NjgiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNjIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mjk5NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjczODczLDAsMCwxLjM1MzcsMCwxMC4wMDAwOTIpIgogICAgICAgeDE9IjgxLjg5OCIKICAgICAgIHkxPSIxNy43MjkiCiAgICAgICB4Mj0iMy4wNDU4IgogICAgICAgeTI9IjE3LjcyOSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2MtNyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDI5OTctMSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjczODczLDAsMCwxLjM1MzcsMCwxMC4wMDAwOTIpIgogICAgICAgeDE9IjgxLjg5ODAwMyIKICAgICAgIHkxPSIxNy43MjkiCiAgICAgICB4Mj0iMy4wNDU4IgogICAgICAgeTI9IjE3LjcyOSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImMtNyIKICAgICAgIHkyPSIxNy43MjkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgyPSIzLjA0NTgiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNzM4NzMsMCwwLDEuMzUzNywwLDIuMDAwMDkxNykiCiAgICAgICB5MT0iMTcuNzI5IgogICAgICAgeDE9IjgxLjg5ODAwMyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNjYzgwMDAiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A3LTQiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNmZmVkMDAiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A5LTAiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjZC00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mjk5My05IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMDAwMDE4OCwwLDAsMS4wMDAwMTg4LDAsMTAuMDAwMDkyKSIKICAgICAgIHgxPSIzNC4yOTAwMDEiCiAgICAgICB5MT0iMzMuNjEyIgogICAgICAgeDI9IjQ4LjI1OTk5OCIKICAgICAgIHkyPSIxLjg0NjgiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJkLTQiCiAgICAgICB5Mj0iMS44NDY4IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4Mj0iNDguMjU5OTk4IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjAwMDAxODgsMCwwLDEuMDAwMDE4OCwwLDIuMDAwMDkxNykiCiAgICAgICB5MT0iMzMuNjEyIgogICAgICAgeDE9IjM0LjI5MDAwMSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNhZjdkMDAiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AxMi04IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZmZlZDAwIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMTQtOCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIHkyPSIxLjg0NjgiCiAgICAgICB4Mj0iNDguMjU5OTk4IgogICAgICAgeTE9IjMzLjYxMiIKICAgICAgIHgxPSIzNC4yOTAwMDEiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMDAwMDE4OCwwLDAsMS4wMDAwMTg4LDAsMTAuMDAwMDkyKSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAyNyIKICAgICAgIHhsaW5rOmhyZWY9IiNkLTQiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNjLTEiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyOTk3LTE3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNzM4NzMsMCwwLDEuMzUzNywwLDEwLjAwMDA5MikiCiAgICAgICB4MT0iODEuODk4MDAzIgogICAgICAgeTE9IjE3LjcyOSIKICAgICAgIHgyPSIzLjA0NTgiCiAgICAgICB5Mj0iMTcuNzI5IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0iYy0xIgogICAgICAgeTI9IjE3LjcyOSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDI9IjMuMDQ1OCIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC43Mzg3MywwLDAsMS4zNTM3LDAsMi4wMDAwOTE3KSIKICAgICAgIHkxPSIxNy43MjkiCiAgICAgICB4MT0iODEuODk4MDAzIj4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2NjODAwMCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDctMSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2ZmZWQwMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDktNSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNkLTciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyOTkzLTIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4wMDAwMTg4LDAsMCwxLjAwMDAxODgsMCwxMC4wMDAwOTIpIgogICAgICAgeDE9IjM0LjI5MDAwMSIKICAgICAgIHkxPSIzMy42MTIiCiAgICAgICB4Mj0iNDguMjU5OTk4IgogICAgICAgeTI9IjEuODQ2OCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImQtNyIKICAgICAgIHkyPSIxLjg0NjgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgyPSI0OC4yNTk5OTgiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMDAwMDE4OCwwLDAsMS4wMDAwMTg4LDAsMi4wMDAwOTE3KSIKICAgICAgIHkxPSIzMy42MTIiCiAgICAgICB4MT0iMzQuMjkwMDAxIj4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2FmN2QwMCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDEyLTYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNmZmVkMDAiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AxNC0xIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjEuODQ2OCIKICAgICAgIHgyPSI0OC4yNTk5OTgiCiAgICAgICB5MT0iMzMuNjEyIgogICAgICAgeDE9IjM0LjI5MDAwMSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4wMDAwMTg4LDAsMCwxLjAwMDAxODgsMCwxMC4wMDAwOTIpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI3LTQiCiAgICAgICB4bGluazpocmVmPSIjZC03IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjZC00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA5MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjE5NDU3OTM4LDAsMCwwLjE5NDU3OTM4LDExLjkyOTE2MywyMi41NDEzMzEpIgogICAgICAgeDE9IjM0LjI5MDAwMSIKICAgICAgIHkxPSIzMy42MTIiCiAgICAgICB4Mj0iNDguMjU5OTk4IgogICAgICAgeTI9IjEuODQ2OCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2QtNyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwOTYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC4xNDM3Mzg5MiwwLDAsMC4yNjMzOTcxNSwxMS45MjkxNjMsMjIuNTQxMzMxKSIKICAgICAgIHgxPSI4MS44OTgwMDMiCiAgICAgICB5MT0iMTcuNzI5IgogICAgICAgeDI9IjMuMDQ1OCIKICAgICAgIHkyPSIxNy43MjkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNkLTciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuMTQzNzM4OTIsMCwwLDAuMjYzMzk3MTUsMTEuOTI5MTYzLDIyLjU0MTMzMSkiCiAgICAgICB4MT0iODEuODk4MDAzIgogICAgICAgeTE9IjE3LjcyOSIKICAgICAgIHgyPSIzLjA0NTgiCiAgICAgICB5Mj0iMTcuNzI5IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjZC00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg3OSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjE5NDU3OTM4LDAsMCwwLjE5NDU3OTM4LDExLjkyOTE2MywyMi41NDEzMzEpIgogICAgICAgeDE9IjM0LjI5MDAwMSIKICAgICAgIHkxPSIzMy42MTIiCiAgICAgICB4Mj0iNDguMjU5OTk4IgogICAgICAgeTI9IjEuODQ2OCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2QtNyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4ODIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC4zNjkxNDY5NiwwLDAsMC4zNjkxNDY5NiwyOC40NTE2NCwxOC4xMzgxOTEpIgogICAgICAgeDE9IjM0LjI5MDAwMSIKICAgICAgIHkxPSIzMy42MTIiCiAgICAgICB4Mj0iNDguMjU5OTk4IgogICAgICAgeTI9IjEuODQ2OCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2QiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODg2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuMjcyNjk0ODEsMCwwLDAuNDk5NzA0ODUsMjguNDUxNjQsMTguMTM4MTkxKSIKICAgICAgIHgxPSI4MS44OTgwMDMiCiAgICAgICB5MT0iMTcuNzI5IgogICAgICAgeDI9IjMuMDQ1OCIKICAgICAgIHkyPSIxNy43MjkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDIzODAiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDIzODIiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2I5Y2ZlNztzdG9wLW9wYWNpdHk6MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyMzg0IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTQ1Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzhhZTIzNDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM5NDciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3M2QyMTY7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzOTQ5IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzkxNiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5NjMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MDAwMDAwNywwLDAsMC43ODQzMTM2OCwwLjIwMDAwMDgyLC0zMC4wOTgwMzgpIgogICAgICAgeDE9IjM3LjI0OTk5NiIKICAgICAgIHkxPSIyNS4wOTIzNDIiCiAgICAgICB4Mj0iMzkuNzQ5OTk2IgogICAgICAgeTI9IjQwLjkyNDk5OSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzkxNiI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzkxOCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojOGFlMjM0O3N0b3Atb3BhY2l0eToxIiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM5MjAiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzRlOWEwNjtzdG9wLW9wYWNpdHk6MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxnCiAgICAgaWQ9Imc0NjA1IgogICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMDg4MzM4NSwwLDAsMS4wODgzMzg1LC00LjMyMjg2MjIsMC42NzQ4NzIzKSI+CiAgICA8ZwogICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMiwyKSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSIzMDAiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iMzAwIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSJDOlxrdzM0bVxtYXVpLW1vZFxwbmdzXG1hY2QucG5nIgogICAgICAgaWQ9ImczMDAwIj4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50Mjk5Nyk7c3Ryb2tlOiM1ZTM4MDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVqb2luOnJvdW5kIgogICAgICAgICBpZD0icGF0aDIwIgogICAgICAgICBkPSJNIDU4Ljc1MDQ1OCwzNS43NTA4NSA0Mi4wMDA0OTQsNDUuMzc1NjU3IDI1LjI1MDUzLDU1LjAwMTgxOCAzLjc0OTc5MzUsNDAuNzUwMDY0IDMuMjUwMDQyNiwyOC4wMDA5MTcgYyAwLDAgMTAuOTE2OTUyNCwtNS4wMDAwMjYgMTYuMzc0Njg5NCwtNy41MDAxNzQgNS40NTgzMjgsLTIuNTAwMDE0IDE2LjM3NDY4OSwtNy41MDAxNzUgMTYuMzc0Njg5LC03LjUwMDE3NSBsIDIzLjQ5OTc0LDEyLjI1MDE3MyAtMC43NTAwMzMsMTAuNTAwMTA5IHoiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMjIiCiAgICAgICAgIGQ9Im0gMy44NzUwMDgyLDI4LjAwMDkxNyBjIDAsMCA3LjA1NTk3OTgsNC41NDQ2NDIgMTAuNTgzNzg0OCw2LjgxNzA5OCAzLjUyODAyNywyLjI3MjMyMSAxMC41ODM3ODUsNi44MTcwOTggMTAuNTgzNzg1LDYuODE3MDk4IGwgLTAuMTY3ODkyLDEzLjExNjI3IgogICAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOm5vbmU7c3Ryb2tlOiM1ZTM4MDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVqb2luOnJvdW5kIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDI0IgogICAgICAgICBkPSJtIDI1LjI3MTIxNSw0MS42ODY4MjQgYyAwLDAgMTEuMzI2MjA4LC01LjUyMDI1MyAxNi45ODkzMTIsLTguMjgwNDQ3IDUuNjYzMTA0LC0yLjc2MDE5NCAxNi45ODkzMTMsLTguMjgwNDQ4IDE2Ljk4OTMxMywtOC4yODA0NDgiCiAgICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2ZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDI5OTMpO3N0cm9rZTojNWUzODAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lam9pbjpyb3VuZCIgLz4KICAgIDwvZz4KICAgIDxnCiAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iMzAwIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjMwMCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iQzpca3czNG1cbWF1aS1tb2RccG5nc1xtYWNkLnBuZyIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0xLDAsMCwxLDM2LjcxMTg2NSwzLjIyMDMzOSkiCiAgICAgICBpZD0iZzM4NzIiPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzODc3KTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzVlMzgwMDtzdHJva2Utd2lkdGg6MC4zODkxNTE0NTtzdHJva2UtbGluZWpvaW46cm91bmQiCiAgICAgICAgIGlkPSJwYXRoMjAtNCIKICAgICAgICAgZD0ibSAyMy4zNjA1NzYsMjcuNTUxODAzIC0zLjI1OTEzNywxLjg3Mjc1NCAtMy4yNTkxMzYsMS44NzMwMTcgLTQuMTgzNTIxLC0yLjc3MzA0NSAtMC4wOTcyNCwtMi40ODA2NzQgYyAwLDAgMi4xMjQxNzQsLTAuOTcyODg0IDMuMTg2MTE3LC0xLjQ1OTM1MiAxLjA2MjA1OCwtMC40ODY0NDIgMy4xODYxMTcsLTEuNDU5MzUyIDMuMTg2MTE3LC0xLjQ1OTM1MiBsIDQuNTcyNDc5LDIuMzgzNTg2IC0wLjE0NTkzOCwyLjA0MzA2NiB6IiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDIyLTUiCiAgICAgICAgIGQ9Im0gMTIuNjgzMTQ2LDI2LjA0Mzg1NSBjIDAsMCAxLjM3MjkyMiwwLjg4NDI3NyAyLjA1OTM0NywxLjMyNjQ0MSAwLjY4NjQ2OCwwLjQ0MjEzOSAyLjA1OTM0OCwxLjMyNjQ0MiAyLjA1OTM0OCwxLjMyNjQ0MiBsIC0wLjAzMjY3LDIuNTUyMTA4IgogICAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOm5vbmU7c3Ryb2tlOiM1ZTM4MDA7c3Ryb2tlLXdpZHRoOjAuMzg5MTUxNDU7c3Ryb2tlLWxpbmVqb2luOnJvdW5kIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDI0LTUiCiAgICAgICAgIGQ9Im0gMTYuODQ2MzI4LDI4LjcwNjggYyAwLDAgMi4yMDM4MDUsLTEuMDc0MTA3IDMuMzA1NzA3LC0xLjYxMTE3NCAxLjEwMTkwMywtMC41MzcwNjcgMy4zMDU3MDgsLTEuNjExMTc0IDMuMzA1NzA4LC0xLjYxMTE3NCIKICAgICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50Mzg3OSk7c3Ryb2tlOiM1ZTM4MDA7c3Ryb2tlLXdpZHRoOjAuMzg5MTUxNDU7c3Ryb2tlLWxpbmVqb2luOnJvdW5kIiAvPgogICAgPC9nPgogICAgPHBhdGgKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSIzMDAiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iMzAwIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSJDOlxrdzM0bVxtYXVpLW1vZFxwbmdzXG1hY2QucG5nIgogICAgICAgZD0ibSA1MC4xMzg3ODUsMjcuNjQzODI2IC02LjE4MzA4MiwzLjU1MjkwMiAtNi4xODMwODIsMy41NTM0MDEgLTcuOTM2NzgyLC01LjI2MDg5MyAtMC4xODQ0NzgsLTQuNzA2MjIgYyAwLDAgNC4wMjk4ODQsLTEuODQ1NzEgNi4wNDQ1NTMsLTIuNzY4NjE0IDIuMDE0ODg3LC0wLjkyMjg1NiA2LjA0NDU1MywtMi43Njg2MTUgNi4wNDQ1NTMsLTIuNzY4NjE1IGwgOC42NzQ2OTQsNC41MjIwMjkgLTAuMjc2ODY3LDMuODc2MDEgeiIKICAgICAgIGlkPSJwYXRoMjAtMiIKICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2ZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM4ODYpO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojNWUzODAwO3N0cm9rZS13aWR0aDowLjczNzk5OTk4O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjMwMCIKICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSIzMDAiCiAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9IkM6XGt3MzRtXG1hdWktbW9kXHBuZ3NcbWFjZC5wbmciCiAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOm5vbmU7c3Ryb2tlOiM1ZTM4MDA7c3Ryb2tlLXdpZHRoOjAuNzM4MjgwMDY7c3Ryb2tlLWxpbmVqb2luOnJvdW5kIgogICAgICAgZD0ibSAyOS44ODIwNjEsMjQuNzgzMDE2IGMgMCwwIDIuNjA0NjQ0LDEuNjc3NjA5IDMuOTA2ODk4LDIuNTE2NDY0IDEuMzAyMzM2LDAuODM4ODA0IDMuOTA2ODk5LDIuNTE2NDYzIDMuOTA2ODk5LDIuNTE2NDYzIGwgLTAuMDYxOTgsNC44NDE3NDEiCiAgICAgICBpZD0icGF0aDIyLTIiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSIzMDAiCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iMzAwIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSJDOlxrdzM0bVxtYXVpLW1vZFxwbmdzXG1hY2QucG5nIgogICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50Mzg4Mik7c3Ryb2tlOiM1ZTM4MDA7c3Ryb2tlLXdpZHRoOjAuNzM4MjgwMDY7c3Ryb2tlLWxpbmVqb2luOnJvdW5kIgogICAgICAgZD0ibSAzNy43ODAyNTcsMjkuODM1MDMyIGMgMCwwIDQuMTgwOTU2LC0yLjAzNzc0NiA2LjI3MTQzNSwtMy4wNTY2NDQgMi4wOTA0NzgsLTEuMDE4ODk4IDYuMjcxNDM1LC0zLjA1NjY0NSA2LjI3MTQzNSwtMy4wNTY2NDUiCiAgICAgICBpZD0icGF0aDI0LTEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogIDwvZz4KICA8ZwogICAgIGlkPSJnMTY5NiIKICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjkxNDM0NzQ4LDAuNjQwMjMzMDIsLTAuNjQwMjMzMDIsMC45MTQzNDc0OCw1Ny45NTAzNCw4LjM0NDYxOTkpIj4KICAgIDxnCiAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7c3Ryb2tlLXdpZHRoOjEuMzI5MDcxNDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgIGlkPSJnMzk1OSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuOTM3NDk5OTQsMCwwLDAuOTM3NDk5OTQsLTU2LjUwNDM5MywyNS44NjI3MTMpIj4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIgogICAgICAgICBpZD0icGF0aDMzNDMtMCIKICAgICAgICAgZD0ibSAzNSwtMTMgdiA0IGMgLTEwLDAgLTE3LDIgLTIzLDcgbCA1LDcgYyA1LjUzMzEwNywtMy4yOTY5MjQzIDExLjMwNDcwMywtNS45MzEzODEzNyAxOCwtNiB2IDQgbCAxNCwtOCB6IgogICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7ZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50Mzk2Myk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMxNzJhMDQ7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIgogICAgICAgICBpZD0icGF0aDMzNDMtMi05IgogICAgICAgICBkPSJtIDM3LC05LjU4MjIzMDQgLTAuMDM0NTMsMi40OTU5MTM3IEMgMjQsLTcgMjAsLTUgMTQuNzQyMzI0LC0xLjYyMTQ4MDUgbCAyLjgyMzg5NywzLjk3NDYxNjkgQyAyMC4yMjQ0MjQsMC45MTM2ODMyNSAyNiwtMyAzNywtMyB2IDIuNTgyMjMwNCBMIDQ1LC01IFoiCiAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOm5vbmU7c3Ryb2tlOiM4YWUyMzQ7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=
"""
-exportPart_b64 =\
-"""
+exportPart_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY4LjI2NjY3IgogICBoZWlnaHQ9IjY4LjI2NjY3IgogICBpZD0ic3ZnMjg2MCIKICAgc29kaXBvZGk6dmVyc2lvbj0iMC4zMiIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45Mi4wIHIxNTI5OSIKICAgc29kaXBvZGk6ZG9jbmFtZT0iZXhwb3J0UGFydF91cGRhdGUuc3ZnIgogICBpbmtzY2FwZTpvdXRwdXRfZXh0ZW5zaW9uPSJvcmcuaW5rc2NhcGUub3V0cHV0LnN2Zy5pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgNjQgNjQiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMyODYyIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzk0NSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM4YWUyMzQ7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzOTQ3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzNkMjE2O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzk0OSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQzODciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQzODkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDM5MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzNzciCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzNjkyIgogICAgICAgY3g9IjQ1Ljg4MzMyNyIKICAgICAgIGN5PSIyOC44Njk1NjgiCiAgICAgICBmeD0iNDUuODgzMzI3IgogICAgICAgZnk9IjI4Ljg2OTU2OCIKICAgICAgIHI9IjE5LjQ2NzQzNiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgtMC4yMzQ0MzIyNCwwLjIzNDQzMTk4KSIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDM4NyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM3MDMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN4PSIxMzEuNDgxODciCiAgICAgICBjeT0iOTMuNTU3Mjg5IgogICAgICAgZng9IjEzMS40ODE4NyIKICAgICAgIGZ5PSI5My41NTcyODkiCiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNTI3MTEwNjQsMS44MTU4ODc0LC0xLjQ1MzQ4NDMsMC40MjE5MTMzMSwyMDMuMjM0MDUsLTE4Ny42NTgzKSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzM3NyI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzM3OSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmFmZjJiO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMzgxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmFhMDA7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDM4NyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM3MDUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN4PSIxNDcuMDU3MTMiCiAgICAgICBjeT0iODMuOTg5MTQzIgogICAgICAgZng9IjE0Ny4wNTcxMyIKICAgICAgIGZ5PSI4My45ODkxNDMiCiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMjk2NjAyOCwwLjE3NzExMjMxLC0wLjE0MDkyODYxLDEuMDMxNzA5NCwtMzIuNjg5OTI5LC0yOS4xMDkyNzQpIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDMxLjk5OTk5OCA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogOTk5Ljk5OTk1IDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjYzLjk5OTk5NyA6IDMxLjk5OTk5OCA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzEuOTk5OTk4IDogMjEuMzMzMzMyIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI4NjgiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzNzctMyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM2OTItNSIKICAgICAgIGN4PSI0NS44ODMzMjciCiAgICAgICBjeT0iMjguODY5NTY4IgogICAgICAgZng9IjQ1Ljg4MzMyNyIKICAgICAgIGZ5PSIyOC44Njk1NjgiCiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTAuMjM0NDMyMjQsMC4yMzQ0MzE5OCkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMzNzctMyI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzM3OS04IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmYWZmMmI7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMzODEtMyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZhYTAwO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtNCkiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzNzY3IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc3MyIKICAgICAgIHgxPSIyMi4xMTY1MTYiCiAgICAgICB5MT0iNTUuNzE3NTE4IgogICAgICAgeDI9IjE3LjMyODU0NyIKICAgICAgIHkyPSIyMS4zMTEzNCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzY3Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM0NjVhNDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM3NjkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNzcxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgwLC00KSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM3NzciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzgzIgogICAgICAgeDE9IjUzLjg5Njc2MyIKICAgICAgIHkxPSI1MS4xNzk3ODciCiAgICAgICB4Mj0iNDcuNTAyMjM1IgogICAgICAgeTI9IjIxLjgzNzQyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NzciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzc3OSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM0NjVhNDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM3ODEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ4NjYyIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50Mzc1NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwwLjUzNjcyMywwLDE2Ljg3MzA2KSIKICAgICAgIGN4PSIyNC44MzcxMjYiCiAgICAgICBjeT0iMzYuNDIxMTI3IgogICAgICAgZng9IjI0LjgzNzEyNiIKICAgICAgIGZ5PSIzNi40MjExMjciCiAgICAgICByPSIxNS42NDQ3MzciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDg2NjIiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDg2NjQiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wODY2NiIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAwMDAwO3N0b3Atb3BhY2l0eTowOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI4NDciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzU5IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKC02NC4yNDc4MTEsNS41ODI1MTM4KSIKICAgICAgIHgxPSIzMi42NDc5NzIiCiAgICAgICB5MT0iMzAuNzQ4ODQ2IgogICAgICAgeDI9IjM3LjEyNDQ2MiIKICAgICAgIHkyPSIyNC44NDIyNTMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI2ODIiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzYxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKC02NC4yNDc4MTEsNS41ODI1MTM4KSIKICAgICAgIHgxPSIzNi43MTM4MzciCiAgICAgICB5MT0iMzEuNDU1OTUyIgogICAgICAgeDI9IjM3LjEyNDQ2MiIKICAgICAgIHkyPSIyNC44NDIyNTMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDI2ODIiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDI2ODQiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzRlOWEwNjtzdG9wLW9wYWNpdHk6MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyNjg2IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM4OWFlZGM7c3RvcC1vcGFjaXR5OjA7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MjQwMiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NjctMyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjE4LjkzNTc2NiIKICAgICAgIHkxPSIyMy42Njc4OTYiCiAgICAgICB4Mj0iNTMuNTg4NjIzIgogICAgICAgeTI9IjI2LjY0OTM2MyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MjQwMiI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMjQwNCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyNDA2IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM1MjhhYzU7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mjg3MSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NjkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSI0Ni44MzQ4MTYiCiAgICAgICB5MT0iNDUuMjY0MTIyIgogICAgICAgeDI9IjQ1LjM4MDQzNiIKICAgICAgIHkyPSI1MC45Mzk2NjciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDI4NzEiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDI4NzMiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM0NjVhNDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMjg3NSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzQ2NWE0O3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzk0NSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NjMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSIxOC45MzU3NjYiCiAgICAgICB5MT0iMjMuNjY3ODk2IgogICAgICAgeDI9IjUzLjU4ODYyMyIKICAgICAgIHkyPSIyNi42NDkzNjMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNDkiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMxNTEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzE1MyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNTI4YWM1O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI3OTciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzcxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iNS45NjQ5MTc3IgogICAgICAgeTE9IjI2LjA0ODE2NCIKICAgICAgIHgyPSI1Mi44NTQwOTUiCiAgICAgICB5Mj0iMjYuMDQ4MTY0IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyNzk3IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyNzk5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDI4MDEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MDsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyODQ3IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc0NSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgtNjMuNzgyMzk4LDUuMzA0OTIwOCkiCiAgICAgICB4MT0iMTMuNDc4NTU0IgogICAgICAgeTE9IjEwLjYxMjIwNiIKICAgICAgIHgyPSIxNS40MTk0MTciCiAgICAgICB5Mj0iMTkuMTE1MTIyIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyODMxIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyODMzIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMzNDY1YTQ7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNWI4NmJlO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwLjMzMzMzMzM0IgogICAgICAgICBpZD0ic3RvcDI4NTUiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMjgzNSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojODNhOGQ4O3N0b3Atb3BhY2l0eTowOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI4NDciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzQ3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0icm90YXRlKDE4MCwtOC4zNTk5NTA1LDI1LjcxNDk2MikiCiAgICAgICB4MT0iMzcuMTI4MDUyIgogICAgICAgeTE9IjI5LjcyOTYwNSIKICAgICAgIHgyPSIzNy4wNjU0MTQiCiAgICAgICB5Mj0iMjYuMTk0MDcxIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyODQ3IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyODQ5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM0ZTlhMDY7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMjg1MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzQ2NWE0O3N0b3Atb3BhY2l0eTowOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDIzODAiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzUzIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iNjIuNTEzODM2IgogICAgICAgeTE9IjM2LjA2MTIzNyIKICAgICAgIHgyPSIxNS45ODQ4NjMiCiAgICAgICB5Mj0iMjAuNjA4NTgiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDIzODAiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDIzODIiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2I5Y2ZlNztzdG9wLW9wYWNpdHk6MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyMzg0IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzOTQ1IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzc0OSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjYyLjUxMzgzNiIKICAgICAgIHkxPSIzNi4wNjEyMzciCiAgICAgICB4Mj0iMTUuOTg0ODYzIgogICAgICAgeTI9IjIwLjYwODU4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTgwIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMTgyIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNiOWNmZTc7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzE4NCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mjc5NyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM3NTUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSI1Ljk2NDkxNzciCiAgICAgICB5MT0iMjYuMDQ4MTY0IgogICAgICAgeDI9IjUyLjg1NDA5NSIKICAgICAgIHkyPSIyNi4wNDgxNjQiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDg2NjIiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzOTY4IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMTMxNDQ2NSwwLDAsMS40NzAxNDI1LDExLjkxMjI4NywtNjkuNzYzNTYpIgogICAgICAgY3g9IjI0LjgzNzEyNiIKICAgICAgIGN5PSIzNi40MjExMjciCiAgICAgICBmeD0iMjQuODM3MTI2IgogICAgICAgZnk9IjM2LjQyMTEyNyIKICAgICAgIHI9IjE1LjY0NDczNyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mjg0NyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5NzAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC43NTk0OTQ2MSwwLDAsMC43NTk0OTQ2MSwtNTguMzk5OTI2LC0wLjE3NjMwODg2KSIKICAgICAgIHgxPSIzMi42NDc5NzIiCiAgICAgICB5MT0iMzAuNzQ4ODQ2IgogICAgICAgeDI9IjM3LjEyNDQ2MiIKICAgICAgIHkyPSIyNC44NDIyNTMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDI2ODIiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTcyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNzU5NDk0NjEsMCwwLDAuNzU5NDk0NjEsLTU4LjM5OTkyNiwtMC4xNzYzMDg4NikiCiAgICAgICB4MT0iMzYuNzEzODM3IgogICAgICAgeTE9IjMxLjQ1NTk1MiIKICAgICAgIHgyPSIzNy4xMjQ0NjIiCiAgICAgICB5Mj0iMjQuODQyMjUzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzOTE2IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzk2MyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgwMDAwMDA3LDAsMCwwLjc4NDMxMzY4LDAuMjAwMDAwODIsLTMwLjA5ODAzOCkiCiAgICAgICB4MT0iMzcuMjQ5OTk2IgogICAgICAgeTE9IjI1LjA5MjM0MiIKICAgICAgIHgyPSIzOS43NDk5OTYiCiAgICAgICB5Mj0iNDAuOTI0OTk5IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTE2Ij4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzOTE4IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM4YWUyMzQ7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzkyMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNGU5YTA2O3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjkuMDgyMDMwOCIKICAgICBpbmtzY2FwZTpjeD0iMzQuMTMzMzM1IgogICAgIGlua3NjYXBlOmN5PSIzNC4xMzMzMzUiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzM5NTEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDAxIgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIgogICAgICAgb3JpZ2lueD0iMCIKICAgICAgIG9yaWdpbnk9IjAiCiAgICAgICBzcGFjaW5neD0iMSIKICAgICAgIHNwYWNpbmd5PSIxIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTI4NjUiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bU3RlZmFuIFRyw7ZnZXJdPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjcmVhdG9yPgogICAgICAgIDxkYzp0aXRsZT5mZW0tYm94PC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDE1LTExLTE1PC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kLzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8Y2M6bGljZW5zZT5odHRwczovL3d3dy5nbnUub3JnL2NvcHlsZWZ0L2xlc3Nlci5odG1sPC9jYzpsaWNlbnNlPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOiM3MjlmY2Y7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gMywxMyAzNywxOSA2MSwxMSAzMSw3IFoiCiAgICAgICBpZD0icGF0aDI5OTMiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50Mzc4Myk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gNjEsMTEgViA0NyBMIDM3LDU3IFYgMTkgWiIKICAgICAgIGlkPSJwYXRoMjk5NSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiCiAgICAgICBpZD0icGF0aDM4MjUiCiAgICAgICBkPSJtIDMsMTMgMzQsNiBWIDU3IEwgMyw1MSBaIgogICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM3NzMpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gNSwxNS40Mjc3MiAwLjAwODY3LDMzLjkxOTExNiAzMC4wMDg2NzEsNS4yNjg3OTkgLTAuMDA4NywtMzMuOTMzNjE0IHoiCiAgICAgICBpZD0icGF0aDM3NjUiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMzQ2NWE0O3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJtIDM5LjAxMjQzLDIwLjQzMzgzMyAtMC4wMTIyNiwzMy41MzUzMDEgMjAuMDAxMTA1LC04LjMwMDk5MyAzLjZlLTQsLTMxLjg2NzM2MyB6IgogICAgICAgaWQ9InBhdGgzNzc1IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICA8ZwogICAgICAgaWQ9ImczOTUxIgogICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoNzMuMjQ0MTQ5LDEyLjI4MDcxNykiPgogICAgICA8ZWxsaXBzZQogICAgICAgICByeT0iMjMuMDAwMDAyIgogICAgICAgICByeD0iMTcuNzAxMTgzIgogICAgICAgICBjeT0iLTE2LjIxOTI4NCIKICAgICAgICAgY3g9IjQwLjAxNDE2OCIKICAgICAgICAgaW5rc2NhcGU6cl9jeT0idHJ1ZSIKICAgICAgICAgaW5rc2NhcGU6cl9jeD0idHJ1ZSIKICAgICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTt2aXNpYmlsaXR5OnZpc2libGU7b3BhY2l0eTowLjM4MzMzMzMzO2ZpbGw6dXJsKCNyYWRpYWxHcmFkaWVudDM5NjgpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjkxNTc3MTAxO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO21hcmtlcjpub25lIgogICAgICAgICBpZD0icGF0aDg2NjAiCiAgICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoLTEpIiAvPgogICAgICA8cGF0aAogICAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmJsb2NrO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM5NzApO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTp1cmwoI2xpbmVhckdyYWRpZW50Mzk3Mik7c3Ryb2tlLXdpZHRoOjAuNzU4MDAwMDI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlcjpub25lIgogICAgICAgICBkPSJtIC0zNi44NDkyNjcsMjUuMjE5MjkyIGMgMCwwIDYuNzg3OTgzLDAuNDc0Njg0IDQuNjk5MzczLC03LjUwMDAwOSBoIDUuOTA1NzQ1IGMgMCwxLjE0MTIxOCAtMC40NDY4NzcsOS4wMTg5OTkgLTEwLjYwNTExOCw3LjUwMDAwOSB6IgogICAgICAgICBpZD0icGF0aDI4MzkiCiAgICAgICAgIGlua3NjYXBlOnJfY3g9InRydWUiCiAgICAgICAgIGlua3NjYXBlOnJfY3k9InRydWUiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjYyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgPGcKICAgICAgICAgaWQ9ImcxNjk2IgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjE0Mzg0ODgsMCwwLDEuMTQzODQ4OCwxLjUyMDAzNTQsLTQuMzk0NjExNykiPgogICAgICAgIDxnCiAgICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO3N0cm9rZS13aWR0aDoxLjMyOTA3MTQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgICAgaWQ9ImczOTU5IgogICAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuOTM3NDk5OTQsMCwwLDAuOTM3NDk5OTQsLTU2LjUwNDM5MywyNS44NjI3MTMpIj4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgICAgICBpZD0icGF0aDMzNDMtMCIKICAgICAgICAgICAgIGQ9Im0gMzUsLTEzIHYgNCBjIC0xMCwwIC0xNywyIC0yMyw3IGwgNSw3IGMgNS41MzMxMDcsLTMuMjk2OTI0MyAxMS4zMDQ3MDMsLTUuOTMxMzgxMzcgMTgsLTYgdiA0IGwgMTQsLTggeiIKICAgICAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzOTYzKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzE3MmEwNDtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgICAgICBpZD0icGF0aDMzNDMtMi05IgogICAgICAgICAgICAgZD0ibSAzNywtOS41ODIyMzA0IC0wLjAzNDUzLDIuNDk1OTEzNyBDIDI0LC03IDIwLC01IDE0Ljc0MjMyNCwtMS42MjE0ODA1IGwgMi44MjM4OTcsMy45NzQ2MTY5IEMgMjAuMjI0NDI0LDAuOTEzNjgzMjUgMjYsLTMgMzcsLTMgdiAyLjU4MjIzMDQgTCA0NSwtNSBaIgogICAgICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO2ZpbGw6bm9uZTtzdHJva2U6IzhhZTIzNDtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgICA8L2c+CiAgICAgIDwvZz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=
"""
-importFP_b64=\
-"""PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIGhlaWdodD0iMjYiCiAgIHdpZHRoPSIyNiIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMjYgMjYiCiAgIGlkPSJzdmcyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkyLjAgcjE1Mjk5IgogICBzb2RpcG9kaTpkb2NuYW1lPSJpbXBvcnRGUC5zdmciPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTEwMCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGUgLz4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxIgogICAgIG9iamVjdHRvbGVyYW5jZT0iMTAiCiAgICAgZ3JpZHRvbGVyYW5jZT0iMTAiCiAgICAgZ3VpZGV0b2xlcmFuY2U9IjEwIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNTM2IgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjgwMSIKICAgICBpZD0ibmFtZWR2aWV3OTgiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6em9vbT0iMTEuODY1Mzg1IgogICAgIGlua3NjYXBlOmN4PSItNS41NzQ0NyIKICAgICBpbmtzY2FwZTpjeT0iMTkuNjgyMDM4IgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmcyIgogICAgIGlua3NjYXBlOnNuYXAtdG8tZ3VpZGVzPSJmYWxzZSIKICAgICBpbmtzY2FwZTpzbmFwLWdyaWRzPSJmYWxzZSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDQ4IgogICAgICAgZW1wc3BhY2luZz0iMSIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxkZWZzCiAgICAgaWQ9ImRlZnM0Ij4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaWQ9ImUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN5PSIyMC40OTM5OTkiCiAgICAgICBjeD0iMzUuMjkyOTk5IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLC0wLjg0MzAyLDEuMDIwMiwwLC00Ljg5NjMyNDksNDEuMDU5NDE4KSIKICAgICAgIHI9IjE2Ljk1NTk5OSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiM3M2QyMTYiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AxMi03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjNGU5YTA2IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMTQtMiIgLz4KICAgIDwvcmFkaWFsR3JhZGllbnQ+CiAgICA8cGF0dGVybgogICAgICAgeT0iMCIKICAgICAgIHg9IjAiCiAgICAgICBoZWlnaHQ9IjYiCiAgICAgICB3aWR0aD0iNiIKICAgICAgIHBhdHRlcm5Vbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iRU1GaGJhc2VwYXR0ZXJuIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyMzgwIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyMzgyIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNiOWNmZTc7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMjM4NCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzk0NSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM4YWUyMzQ7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzOTQ3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzNkMjE2O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzk0OSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM5MTYiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTYzIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuODAwMDAwMDcsMCwwLDAuNzg0MzEzNjgsMC4yMDAwMDA4MiwtMzAuMDk4MDM4KSIKICAgICAgIHgxPSIzNy4yNDk5OTYiCiAgICAgICB5MT0iMjUuMDkyMzQyIgogICAgICAgeDI9IjM5Ljc0OTk5NiIKICAgICAgIHkyPSI0MC45MjQ5OTkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5MTYiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM5MTgiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzhhZTIzNDtzdG9wLW9wYWNpdHk6MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzOTIwIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM0ZTlhMDY7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogIDwvZGVmcz4KICA8ZwogICAgIGlkPSJnOTE5IgogICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMSkiPgogICAgPHJlY3QKICAgICAgIGlkPSJyZWN0NTEiCiAgICAgICB4PSItMjAuNTkzNTY1IgogICAgICAgeT0iMS40OTQ3NDkzIgogICAgICAgd2lkdGg9IjE0LjA4ODY5IgogICAgICAgaGVpZ2h0PSIyMi45MjQzNTUiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtOTApIgogICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjtzdHJva2U6IzU0NTQ1NDtzdHJva2Utd2lkdGg6MC45NzcxMTI4OTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgIDxwYXRoCiAgICAgICBpZD0icGF0aDUzIgogICAgICAgZD0ibSAwLjk4NjIzOTI0LDExLjA4MjEyNiBhIDIuMjI0MDU4MSwxLjk1ODk0NDkgMCAxIDEgMC4wMTM3NjAxLDMuOTE3ODcxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM1NDU0NTQ7c3Ryb2tlLXdpZHRoOjE7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICA8ZwogICAgICAgaWQ9ImczOTgzIj4KICAgICAgPHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwYzkyMTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzU0NTQ1NDtzdHJva2Utd2lkdGg6MC45MzI0MTMyMjtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJyb3RhdGUoLTkwKSIKICAgICAgICAgaGVpZ2h0PSI0LjA2NTk3MDkiCiAgICAgICAgIHdpZHRoPSI2LjA1OTA4MzUiCiAgICAgICAgIHk9IjQuNTEyMzQwMSIKICAgICAgICAgeD0iLTguNTMxNzc2NCIKICAgICAgICAgaWQ9InJlY3Q3MyIgLz4KICAgICAgPHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwYzkyMTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzU0NTQ1NDtzdHJva2Utd2lkdGg6MC45MzI0MTMyMjtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJyb3RhdGUoLTkwKSIKICAgICAgICAgaGVpZ2h0PSI0LjA2NTk3MDkiCiAgICAgICAgIHdpZHRoPSI2LjA1OTA4MzUiCiAgICAgICAgIHk9IjExLjQ1MTYxNyIKICAgICAgICAgeD0iLTguNTA3NjYxOCIKICAgICAgICAgaWQ9InJlY3Q3My01IiAvPgogICAgICA8cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojMDBjOTIxO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojNTQ1NDU0O3N0cm9rZS13aWR0aDowLjkzMjQxMzIyO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtOTApIgogICAgICAgICBoZWlnaHQ9IjQuMDY1OTcwOSIKICAgICAgICAgd2lkdGg9IjYuMDU5MDgzNSIKICAgICAgICAgeT0iMTguNDg4ODk1IgogICAgICAgICB4PSItOC41NDk4MDA5IgogICAgICAgICBpZD0icmVjdDczLTU2IiAvPgogICAgPC9nPgogICAgPHJlY3QKICAgICAgIGlkPSJyZWN0NzMtMCIKICAgICAgIHg9Ii0yNC42MjI2MjUiCiAgICAgICB5PSI0LjU2NjE4ODgiCiAgICAgICB3aWR0aD0iNi4wNTkwODM1IgogICAgICAgaGVpZ2h0PSI0LjA2NTk3MDkiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtOTApIgogICAgICAgc3R5bGU9ImZpbGw6IzAwYzkyMTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzU0NTQ1NDtzdHJva2Utd2lkdGg6MC45MzI0MTMyMjtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgIDxyZWN0CiAgICAgICBpZD0icmVjdDczLTUtNCIKICAgICAgIHg9Ii0yNC41OTg1MTEiCiAgICAgICB5PSIxMS41MDU0NjYiCiAgICAgICB3aWR0aD0iNi4wNTkwODM1IgogICAgICAgaGVpZ2h0PSI0LjA2NTk3MDkiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtOTApIgogICAgICAgc3R5bGU9ImZpbGw6IzAwYzkyMTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzU0NTQ1NDtzdHJva2Utd2lkdGg6MC45MzI0MTMyMjtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgIDxyZWN0CiAgICAgICBpZD0icmVjdDczLTU2LTkiCiAgICAgICB4PSItMjQuNjQwNjUiCiAgICAgICB5PSIxOC41NDI3NDQiCiAgICAgICB3aWR0aD0iNi4wNTkwODM1IgogICAgICAgaGVpZ2h0PSI0LjA2NTk3MDkiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtOTApIgogICAgICAgc3R5bGU9ImZpbGw6IzAwYzkyMTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzU0NTQ1NDtzdHJva2Utd2lkdGg6MC45MzI0MTMyMjtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICA8L2c+CiAgPGcKICAgICBpZD0iZzE2OTYiCiAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC40OTMwNzQzNCwwLjM0NTI1NDM5LC0wLjM0NTI1NDM5LDAuNDkzMDc0MzQsMzEuMzM5MDIyLDQuNDk3NDA5NikiPgogICAgPGcKICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtzdHJva2Utd2lkdGg6MS4zMjkwNzE0O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgaWQ9ImczOTU5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC45Mzc0OTk5NCwwLDAsMC45Mzc0OTk5NCwtNTYuNTA0MzkzLDI1Ljg2MjcxMykiPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoMzM0My0wIgogICAgICAgICBkPSJtIDM1LC0xMyB2IDQgYyAtMTAsMCAtMTcsMiAtMjMsNyBsIDUsNyBjIDUuNTMzMTA3LC0zLjI5NjkyNDMgMTEuMzA0NzAzLC01LjkzMTM4MTM3IDE4LC02IHYgNCBsIDE0LC04IHoiCiAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzOTYzKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzE3MmEwNDtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoMzM0My0yLTkiCiAgICAgICAgIGQ9Im0gMzcsLTkuNTgyMjMwNCAtMC4wMzQ1MywyLjQ5NTkxMzcgQyAyNCwtNyAyMCwtNSAxNC43NDIzMjQsLTEuNjIxNDgwNSBsIDIuODIzODk3LDMuOTc0NjE2OSBDIDIwLjIyNDQyNCwwLjkxMzY4MzI1IDI2LC0zIDM3LC0zIHYgMi41ODIyMzA0IEwgNDUsLTUgWiIKICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO2ZpbGw6bm9uZTtzdHJva2U6IzhhZTIzNDtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPC9nPgogIDwvZz4KPC9zdmc+Cg==
-"""
-collisions_b64=\
+importFP_b64 = """PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIGhlaWdodD0iMjYiCiAgIHdpZHRoPSIyNiIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMjYgMjYiCiAgIGlkPSJzdmcyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjkyLjAgcjE1Mjk5IgogICBzb2RpcG9kaTpkb2NuYW1lPSJpbXBvcnRGUC5zdmciPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTEwMCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGUgLz4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxIgogICAgIG9iamVjdHRvbGVyYW5jZT0iMTAiCiAgICAgZ3JpZHRvbGVyYW5jZT0iMTAiCiAgICAgZ3VpZGV0b2xlcmFuY2U9IjEwIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNTM2IgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjgwMSIKICAgICBpZD0ibmFtZWR2aWV3OTgiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6em9vbT0iMTEuODY1Mzg1IgogICAgIGlua3NjYXBlOmN4PSItNS41NzQ0NyIKICAgICBpbmtzY2FwZTpjeT0iMTkuNjgyMDM4IgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmcyIgogICAgIGlua3NjYXBlOnNuYXAtdG8tZ3VpZGVzPSJmYWxzZSIKICAgICBpbmtzY2FwZTpzbmFwLWdyaWRzPSJmYWxzZSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDQ4IgogICAgICAgZW1wc3BhY2luZz0iMSIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxkZWZzCiAgICAgaWQ9ImRlZnM0Ij4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaWQ9ImUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN5PSIyMC40OTM5OTkiCiAgICAgICBjeD0iMzUuMjkyOTk5IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLC0wLjg0MzAyLDEuMDIwMiwwLC00Ljg5NjMyNDksNDEuMDU5NDE4KSIKICAgICAgIHI9IjE2Ljk1NTk5OSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiM3M2QyMTYiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AxMi03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjNGU5YTA2IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMTQtMiIgLz4KICAgIDwvcmFkaWFsR3JhZGllbnQ+CiAgICA8cGF0dGVybgogICAgICAgeT0iMCIKICAgICAgIHg9IjAiCiAgICAgICBoZWlnaHQ9IjYiCiAgICAgICB3aWR0aD0iNiIKICAgICAgIHBhdHRlcm5Vbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0iRU1GaGJhc2VwYXR0ZXJuIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyMzgwIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyMzgyIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNiOWNmZTc7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMjM4NCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzk0NSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM4YWUyMzQ7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzOTQ3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzNkMjE2O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzk0OSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM5MTYiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTYzIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuODAwMDAwMDcsMCwwLDAuNzg0MzEzNjgsMC4yMDAwMDA4MiwtMzAuMDk4MDM4KSIKICAgICAgIHgxPSIzNy4yNDk5OTYiCiAgICAgICB5MT0iMjUuMDkyMzQyIgogICAgICAgeDI9IjM5Ljc0OTk5NiIKICAgICAgIHkyPSI0MC45MjQ5OTkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5MTYiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM5MTgiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzhhZTIzNDtzdG9wLW9wYWNpdHk6MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzOTIwIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM0ZTlhMDY7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogIDwvZGVmcz4KICA8ZwogICAgIGlkPSJnOTE5IgogICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsMSkiPgogICAgPHJlY3QKICAgICAgIGlkPSJyZWN0NTEiCiAgICAgICB4PSItMjAuNTkzNTY1IgogICAgICAgeT0iMS40OTQ3NDkzIgogICAgICAgd2lkdGg9IjE0LjA4ODY5IgogICAgICAgaGVpZ2h0PSIyMi45MjQzNTUiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtOTApIgogICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjtzdHJva2U6IzU0NTQ1NDtzdHJva2Utd2lkdGg6MC45NzcxMTI4OTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgIDxwYXRoCiAgICAgICBpZD0icGF0aDUzIgogICAgICAgZD0ibSAwLjk4NjIzOTI0LDExLjA4MjEyNiBhIDIuMjI0MDU4MSwxLjk1ODk0NDkgMCAxIDEgMC4wMTM3NjAxLDMuOTE3ODcxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM1NDU0NTQ7c3Ryb2tlLXdpZHRoOjE7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICA8ZwogICAgICAgaWQ9ImczOTgzIj4KICAgICAgPHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwYzkyMTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzU0NTQ1NDtzdHJva2Utd2lkdGg6MC45MzI0MTMyMjtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJyb3RhdGUoLTkwKSIKICAgICAgICAgaGVpZ2h0PSI0LjA2NTk3MDkiCiAgICAgICAgIHdpZHRoPSI2LjA1OTA4MzUiCiAgICAgICAgIHk9IjQuNTEyMzQwMSIKICAgICAgICAgeD0iLTguNTMxNzc2NCIKICAgICAgICAgaWQ9InJlY3Q3MyIgLz4KICAgICAgPHJlY3QKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwYzkyMTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzU0NTQ1NDtzdHJva2Utd2lkdGg6MC45MzI0MTMyMjtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgdHJhbnNmb3JtPSJyb3RhdGUoLTkwKSIKICAgICAgICAgaGVpZ2h0PSI0LjA2NTk3MDkiCiAgICAgICAgIHdpZHRoPSI2LjA1OTA4MzUiCiAgICAgICAgIHk9IjExLjQ1MTYxNyIKICAgICAgICAgeD0iLTguNTA3NjYxOCIKICAgICAgICAgaWQ9InJlY3Q3My01IiAvPgogICAgICA8cmVjdAogICAgICAgICBzdHlsZT0iZmlsbDojMDBjOTIxO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojNTQ1NDU0O3N0cm9rZS13aWR0aDowLjkzMjQxMzIyO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtOTApIgogICAgICAgICBoZWlnaHQ9IjQuMDY1OTcwOSIKICAgICAgICAgd2lkdGg9IjYuMDU5MDgzNSIKICAgICAgICAgeT0iMTguNDg4ODk1IgogICAgICAgICB4PSItOC41NDk4MDA5IgogICAgICAgICBpZD0icmVjdDczLTU2IiAvPgogICAgPC9nPgogICAgPHJlY3QKICAgICAgIGlkPSJyZWN0NzMtMCIKICAgICAgIHg9Ii0yNC42MjI2MjUiCiAgICAgICB5PSI0LjU2NjE4ODgiCiAgICAgICB3aWR0aD0iNi4wNTkwODM1IgogICAgICAgaGVpZ2h0PSI0LjA2NTk3MDkiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtOTApIgogICAgICAgc3R5bGU9ImZpbGw6IzAwYzkyMTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzU0NTQ1NDtzdHJva2Utd2lkdGg6MC45MzI0MTMyMjtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgIDxyZWN0CiAgICAgICBpZD0icmVjdDczLTUtNCIKICAgICAgIHg9Ii0yNC41OTg1MTEiCiAgICAgICB5PSIxMS41MDU0NjYiCiAgICAgICB3aWR0aD0iNi4wNTkwODM1IgogICAgICAgaGVpZ2h0PSI0LjA2NTk3MDkiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtOTApIgogICAgICAgc3R5bGU9ImZpbGw6IzAwYzkyMTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzU0NTQ1NDtzdHJva2Utd2lkdGg6MC45MzI0MTMyMjtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgIDxyZWN0CiAgICAgICBpZD0icmVjdDczLTU2LTkiCiAgICAgICB4PSItMjQuNjQwNjUiCiAgICAgICB5PSIxOC41NDI3NDQiCiAgICAgICB3aWR0aD0iNi4wNTkwODM1IgogICAgICAgaGVpZ2h0PSI0LjA2NTk3MDkiCiAgICAgICB0cmFuc2Zvcm09InJvdGF0ZSgtOTApIgogICAgICAgc3R5bGU9ImZpbGw6IzAwYzkyMTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzU0NTQ1NDtzdHJva2Utd2lkdGg6MC45MzI0MTMyMjtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICA8L2c+CiAgPGcKICAgICBpZD0iZzE2OTYiCiAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC40OTMwNzQzNCwwLjM0NTI1NDM5LC0wLjM0NTI1NDM5LDAuNDkzMDc0MzQsMzEuMzM5MDIyLDQuNDk3NDA5NikiPgogICAgPGcKICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtzdHJva2Utd2lkdGg6MS4zMjkwNzE0O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgaWQ9ImczOTU5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC45Mzc0OTk5NCwwLDAsMC45Mzc0OTk5NCwtNTYuNTA0MzkzLDI1Ljg2MjcxMykiPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoMzM0My0wIgogICAgICAgICBkPSJtIDM1LC0xMyB2IDQgYyAtMTAsMCAtMTcsMiAtMjMsNyBsIDUsNyBjIDUuNTMzMTA3LC0zLjI5NjkyNDMgMTEuMzA0NzAzLC01LjkzMTM4MTM3IDE4LC02IHYgNCBsIDE0LC04IHoiCiAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzOTYzKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzE3MmEwNDtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoMzM0My0yLTkiCiAgICAgICAgIGQ9Im0gMzcsLTkuNTgyMjMwNCAtMC4wMzQ1MywyLjQ5NTkxMzcgQyAyNCwtNyAyMCwtNSAxNC43NDIzMjQsLTEuNjIxNDgwNSBsIDIuODIzODk3LDMuOTc0NjE2OSBDIDIwLjIyNDQyNCwwLjkxMzY4MzI1IDI2LC0zIDM3LC0zIHYgMi41ODIyMzA0IEwgNDUsLTUgWiIKICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO2ZpbGw6bm9uZTtzdHJva2U6IzhhZTIzNDtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPC9nPgogIDwvZz4KPC9zdmc+Cg==
"""
+collisions_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI1NjgiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9IkNvbGxpc2lvbnMuc3ZnIgogICBpbmtzY2FwZTpvdXRwdXRfZXh0ZW5zaW9uPSJvcmcuaW5rc2NhcGUub3V0cHV0LnN2Zy5pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzMjU3MCI+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDg0NiI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZjAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wODQyIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmYwMDAwO3N0b3Atb3BhY2l0eTowOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDg0NCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NjQiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4NjYiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcxYjJmODtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2OCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAyNzk1O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM1OTMiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYzhlMGY5O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM1OTUiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM2MzdkY2E7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzU5NyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iNjQgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzIgOiAyMS4zMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjU3NiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzE0MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMzNDY1YTQ7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMTQ1IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzE0NyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNDMtNyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMTQ1LTAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMTQ3LTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICByPSIxOS41NzE0MjgiCiAgICAgICBmeT0iMjYuMjgxNzQ0IgogICAgICAgZng9IjQ2LjUzNDEzNCIKICAgICAgIGN5PSIyNi4yODE3NDQiCiAgICAgICBjeD0iNDYuNTM0MTM0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMDkwLTMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMTQzLTYiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMTQ4NjA4OCwxLjg0Nzc2MTcsLTMuMDU2NjczLDEuOTAwMDk0LDczLjI1Nzc0NSwtMTEyLjEwMTYpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTQzLTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzE0NS03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZDNkN2NmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzE0Ny01IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgcj0iMTkuNTcxNDI4IgogICAgICAgZnk9IjI2LjI4MTc0NCIKICAgICAgIGZ4PSI0Ni41MzQxMzQiCiAgICAgICBjeT0iMjYuMjgxNzQ0IgogICAgICAgY3g9IjQ2LjUzNDEzNCIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4xNDg2MDg4LDEuODQ3NzYxNywtMy4wNTY2NzMsMS45MDAwOTQsNzMuMjU3NzQ1LC0xMTIuMTAxNikiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMwMTciCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMTQzLTYiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIHI9IjE5LjU3MTQyOCIKICAgICAgIGZ5PSIyNi4yODE3NDQiCiAgICAgICBmeD0iNDYuNTM0MTM0IgogICAgICAgY3k9IjI2LjI4MTc0NCIKICAgICAgIGN4PSI0Ni41MzQxMzQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMwOTAtNSIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMxNDMtNjIiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMTQ4NjA4OCwxLjg0Nzc2MTcsLTMuMDU2NjczLDEuOTAwMDk0LDczLjI1Nzc0NSwtMTEyLjEwMTYpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTQzLTYyIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDMxNDUtOSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2QzZDdjZjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDMxNDctMSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIHI9IjE5LjU3MTQyOCIKICAgICAgIGZ5PSIyNi4yODE3NDQiCiAgICAgICBmeD0iNDYuNTM0MTM0IgogICAgICAgY3k9IjI2LjI4MTc0NCIKICAgICAgIGN4PSI0Ni41MzQxMzQiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMTQ4NjA4OCwxLjg0Nzc2MTcsLTMuMDU2NjczLDEuOTAwMDk0LDczLjI1Nzc0NSwtMTEyLjEwMTYpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMDE3LTIiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMTQzLTYyIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ4NDYiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ4NDgiCiAgICAgICB4MT0iMjQiCiAgICAgICB5MT0iMzAiCiAgICAgICB4Mj0iNDAiCiAgICAgICB5Mj0iNDAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjQuNzIzMjE2MSIKICAgICBpbmtzY2FwZTpjeD0iMzEuNjg2NDg1IgogICAgIGlua3NjYXBlOmN5PSI0OC42MzU3NTUiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzM1NjAiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQyOTk2IgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTI1NzMiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6dGl0bGU+UGFydF9Db21tb248L2RjOnRpdGxlPgogICAgICAgIDxkYzpkYXRlPjIwMTEtMTAtMTA8L2RjOmRhdGU+CiAgICAgICAgPGRjOnJlbGF0aW9uPmh0dHA6Ly93d3cuZnJlZWNhZHdlYi5vcmcvd2lraS9pbmRleC5waHA/dGl0bGU9QXJ0d29yazwvZGM6cmVsYXRpb24+CiAgICAgICAgPGRjOnB1Ymxpc2hlcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkZyZWVDQUQ8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnB1Ymxpc2hlcj4KICAgICAgICA8ZGM6aWRlbnRpZmllcj5GcmVlQ0FEL3NyYy9Nb2QvUGFydC9HdWkvUmVzb3VyY2VzL2ljb25zL1BhcnRfQ29tbW9uLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8Y2M6bGljZW5zZT5odHRwczovL3d3dy5nbnUub3JnL2NvcHlsZWZ0L2xlc3Nlci5odG1sPC9jYzpsaWNlbnNlPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPGcKICAgICAgIGlkPSJnMzU2MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuOTEyNzM2MTgsMCwwLDAuOTAzNDk1MTUsMTA1Ljg1Mzc0LDIuODAwMzYzKSI+CiAgICAgIDxwYXRoCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMTIwOTIyMSwwLDAsMS4xMzIzNTQ2LC0xNTEuNTIwMzksMi4wMjU5MikiCiAgICAgICAgIGQ9Ik0gNzEuNzg1NzE1LDM0LjU3MTQyNiBBIDE4LjU3MTQyOCwxOC41NzE0MjggMCAwIDEgNTMuMjE0Mjg3LDUzLjE0Mjg1NSAxOC41NzE0MjgsMTguNTcxNDI4IDAgMCAxIDM0LjY0Mjg1OSwzNC41NzE0MjYgMTguNTcxNDI4LDE4LjU3MTQyOCAwIDAgMSA1My4yMTQyODcsMTUuOTk5OTk4IDE4LjU3MTQyOCwxOC41NzE0MjggMCAwIDEgNzEuNzg1NzE1LDM0LjU3MTQyNiBaIgogICAgICAgICBzb2RpcG9kaTpyeT0iMTguNTcxNDI4IgogICAgICAgICBzb2RpcG9kaTpyeD0iMTguNTcxNDI4IgogICAgICAgICBzb2RpcG9kaTpjeT0iMzQuNTcxNDI2IgogICAgICAgICBzb2RpcG9kaTpjeD0iNTMuMjE0Mjg3IgogICAgICAgICBpZD0icGF0aDM1NTAtMy03IgogICAgICAgICBzdHlsZT0iZmlsbDp1cmwoI3JhZGlhbEdyYWRpZW50MzAxNy0yKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzJlMzQzNjtzdHJva2Utd2lkdGg6MS45NTI3MzcyMTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIKICAgICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIiAvPgogICAgICA8cGF0aAogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjEyMDk1NDEsMCwwLDEuMTMyNDE5NCwtMTMxLjgwMDU4LC0xMy40NzI4OTYpIgogICAgICAgICBkPSJNIDcxLjc4NTcxNSwzNC41NzE0MjYgQSAxOC41NzE0MjgsMTguNTcxNDI4IDAgMCAxIDUzLjIxNDI4Nyw1My4xNDI4NTUgMTguNTcxNDI4LDE4LjU3MTQyOCAwIDAgMSAzNC42NDI4NTksMzQuNTcxNDI2IDE4LjU3MTQyOCwxOC41NzE0MjggMCAwIDEgNTMuMjE0Mjg3LDE1Ljk5OTk5OCAxOC41NzE0MjgsMTguNTcxNDI4IDAgMCAxIDcxLjc4NTcxNSwzNC41NzE0MjYgWiIKICAgICAgICAgc29kaXBvZGk6cnk9IjE4LjU3MTQyOCIKICAgICAgICAgc29kaXBvZGk6cng9IjE4LjU3MTQyOCIKICAgICAgICAgc29kaXBvZGk6Y3k9IjM0LjU3MTQyNiIKICAgICAgICAgc29kaXBvZGk6Y3g9IjUzLjIxNDI4NyIKICAgICAgICAgaWQ9InBhdGgzNTUwLTMtMyIKICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNyYWRpYWxHcmFkaWVudDMwMTcpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMmUzNDM2O3N0cm9rZS13aWR0aDoxLjk1MjY1MzQxO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIgogICAgICAgICBzb2RpcG9kaTp0eXBlPSJhcmMiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQ4NDgpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojODUxNTIxO3N0cm9rZS13aWR0aDoxLjk5NzgyODcyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIgogICAgICAgICBkPSJNIDIyIDIxIEMgMjEuODgzMzk2IDIxIDIxLjc3MjM1NCAyMS4wMjkxNTggMjEuNjU2MjUgMjEuMDMxMjUgQyAyMS4yMjg4NTIgMjIuNjE0MTMxIDIxIDI0LjI4MjAwNCAyMSAyNiBDIDIxIDM2LjQ5NDAxIDI5LjUwNTk5MSA0NSA0MCA0NSBDIDQwLjExNjYwNCA0NSA0MC4yMjc2NDYgNDQuOTcwODQyIDQwLjM0Mzc1IDQ0Ljk2ODc1IEMgNDAuNzcxMTQ4IDQzLjM4NTg2OSA0MSA0MS43MTc5OTYgNDEgNDAgQyA0MSAyOS41MDU5OSAzMi40OTQwMDkgMjEgMjIgMjEgeiAiCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMDk1NjA2OCwwLDAsMS4xMDY4MTI4LC0xMTUuOTc0MDgsLTMuMDk5NDc3NikiCiAgICAgICAgIGlkPSJwYXRoMzU1MC0zIiAvPgogICAgICA8cGF0aAogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZmYyYzJjO3N0cm9rZS13aWR0aDoxLjk5NzgyODY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiCiAgICAgICAgIGQ9Ik0gMjMuMjgxMjUgMjMuMDYyNSBDIDIzLjExNTQ5OCAyNC4wMTU0NjggMjMgMjQuOTk5NjE1IDIzIDI2IEMgMjMgMzQuOTU5ODk5IDI5LjkyNTcxNyA0Mi4yODQ1ODcgMzguNzE4NzUgNDIuOTM3NSBDIDM4Ljg4NDUwMiA0MS45ODQ1MzIgMzkgNDEuMDAwMzg1IDM5IDQwIEMgMzkgMzEuMDQwMTAxIDMyLjA3NDI4MyAyMy43MTU0MTMgMjMuMjgxMjUgMjMuMDYyNSB6ICIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4wOTU2MDY4LDAsMCwxLjEwNjgxMjgsLTExNS45NzQwOCwtMy4wOTk0Nzc2KSIKICAgICAgICAgaWQ9InBhdGgzNTUwLTMtMSIgLz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=
"""
-export3DModel_b64=\
-"""
+export3DModel_b64 = """
iVBORw0KGgoAAAANSUhEUgAAABoAAAAaCAYAAACpSkzOAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAUBSURBVEiJtZVtiFzVGcd/577M3Xm5M7OzMzs7s5u4myWY7ULBGDG120akDfRbhQj90qIIkZAvCir9IMF+KIV+aDVCkNDQL0UtikKLqAGpsVIbUHxZzMTpromy2ZfMvkz27syd+/r0w+7MrgQ0kfiHA5fzwPmd//+55xzFlo4fP/77KIqejOPYANA0LUwkEn84efLkiVtRN7qgKIqeOHbsmGHbNgCO4xinTp36LXDiVtR7oDiOzVwuRyKRYGtHiIh5q+pGtVp9GqBer3PmzBl0Xe86pF6vc6vqqlqtyuHDh/k+dfbs2c3oRkdHcRznphcIgpDG6jrLjo8YfYjEqMgnldCxkzo5O027tQHs6NGNgi58scCq45EfHCZTHKZ8+xSTlTG0rcgA2utrOCuL/Pu9f7K83CBO794G3aiyo/uZmPgRztoSHeca8/WPqf3nTVJ2lureO2g5a8x8+gGkypiDBxjeU+bqR6/cPChhJUnlSiSzRUQEUAB4rsN64wozXyyRGv85AiBCFEcIgmFZFjMzM0RRRPcMfJMkBs8PiGNBZHvEYtKXLaGMBFEUbm5CBJQCEYx8Pk+tVgNgZGSEcrn8jaA4jvG8kCiKtiD0YJrEiAhRuA1SmgYChlKqt0iz2fxWkIjg+T5hGH/NkQhYetQD0YXrOkKMISJ0Yblc7luji0XwvJAgCK9zpFuCSEwUBtCdh01HzWaTqakpwjC8oR7FkeD5Ab4fXueoz1BIDPEOR2y2CMPzPMbHx5m7MseH9XM47jKu7yJbW0mYCZKJDNnkAAV7kNAuYACe5xPvdBQLoWX2otOUhmmZiNsgdOZ3/N4izDVmOfRIhV0/LKHpCgSCjuAs+cxNX2X6nTp++xyZ2ZcpVqfor9yNlhrAsDK03YCgs4REy1h9BTR3jqRziWKfx3RncRvUbruYhsnIZJLS7hQdL0Apha4rhvamuP1QgfuOD7Ox6nPxX+u8/7eXWJh9lYH0OLo2gpGrsrD4Or67wljxJ+weKqL6UzhOBGxdQZcvX2ZlZQVDN9hYC8gPh8xfbqDpGvrWMBI6yZRFMmNx15ESd95fZPb8Nd7600UI/0fGHSDwGgyMJWkufk5mVftab3XbttXs7Oy5fD5/r9YXktnjU91r43dCjISOUgoRCP0IrxPgtjw6rofSFIPjGe46UiI/bFA7v8gvHt/FgQdKvPf3S9xz5yEWF65Sq9V+B5zrHaKjR4+Kb60yn36HqQerm7GZGoah93roeSGdlofb9gmDEMPUsfMp0ukkkcRomkIpxbt/WcCrVRjr38/p06dVLzoATdOCQrZovvFak0/+0exZ7rP1oDBqxtV9aWvXHWmG9mbIDWTwvZCNa23WGg7rqy2yhQxWn0kUxxz89SDPH5nG3JOLetF1Pw4ePGi5TnBPpXCbNjq0j7HKRDiQG3xhbv7L59avhtPeFbt84e2V0n9fXOTSeQd7UGdoj42dTxMGIc2VFq11l6ATkc0nyVYN3n/jopscDJ5tLRFs3z83qKHJxA9E4l9quhwzknrlZ49WtIkfl5Rzrc3SlVV0Xae/ZJPtT/PXhy8EzcXgj0ufhU/dNKiryUkSK8r46sCvCsWf/ma37m54BEGIUgqlKzJ2kvnPHV58bDZAGftu+j3qqiHmQ0qknKuYzNWaaIaGUoBSKKC9uoFhQaZg6q1m8Mx3dlSeMP6MzsN0X74dum5CZPn/vEjUhOHm6mAAAAAASUVORK5CYII=
"""
-virtual_b64=\
-"""
+virtual_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB3aWR0aD0iNDgiCiAgIGhlaWdodD0iNDgiCiAgIHZpZXdCb3g9IjAgMCA0OC4wMDAwMDEgNDguMDAwMDAxIgogICBpZD0ic3ZnMTU4MjUiCiAgIHZlcnNpb249IjEuMSIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45Mi4wIHIxNTI5OSIKICAgc29kaXBvZGk6ZG9jbmFtZT0ibWVjaGFuaWNhbC5zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMxNTgyNyIgLz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6em9vbT0iMTIuNjI1IgogICAgIGlua3NjYXBlOmN4PSIxMC40OTUwNSIKICAgICBpbmtzY2FwZTpjeT0iMjQiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgdW5pdHM9InB4IgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTI2MCIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI3ODciCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjE4NCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iODciCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMCIgLz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGExNTgzMCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGU+PC9kYzp0aXRsZT4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIGlkPSJsYXllcjEiCiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwtMTAwNC4zNjIyKSI+CiAgICA8ZwogICAgICAgaWQ9Imc3ODQ3IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS42ODA5MDc0LDAsMCwxLjY4MDkwNzQsLTMyLjcwNTkzOSwtNjk5Ljc5OTc3KSIKICAgICAgIHN0eWxlPSJzdHJva2Utd2lkdGg6MC41OTQ5MTY3NztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSI+CiAgICAgIDxwYXRoCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjY2NjY2NjYyIKICAgICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCwxMDA0LjM2MjIpIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDc4NDUiCiAgICAgICAgIGQ9Im0gMjYuNDYxMTA3LDEzLjM0MDgzMSBjIC0xLjM2MTU2NywxLjcyOTgzMyAtMi4xNzIzNzYsMy42NjI3NzIgLTQuMTE4MDM4LDguMDg1NzA1IC0wLjQ4NjkzMiwxLjY3MDkyOCAtMC43MjYwODMsMi42MTc4ODkgLTAuNTY5MDcyLDUuOTA4OTYzIDIuMzcyMzk2LDIuOTIzMTc2IDYuMzQxMjI4LDYuNzA0MjAyIDcuODQ5NTQ5LDcuMDUwMDQxIDEuOTczMDQsMC40NDg0NzkgOS45MDc3OSwtMC42OTQzOTIgMTEuODkwMTYxLC0xLjA2NjIxMSAxLjc5NzkzMiwtMi43ODYzMjMgMy4zMTI2NzMsLTYuMTAyNDczIDQuNTExNjAyLC04LjU3MjcwOSAwLjA0NjE4LC0yLjEwOTU4NiAtMC4wMDYsLTMuMTI4ODk1IC0wLjAwNTEsLTUuMTk1MjM2IC0xLjQ0NzIxNCwtMi42NDMwMiAtNC45MjA1NjMsLTQuOTQ0OTQzIC03LjYxOTU4NiwtNy4wNDQ3MSAtMy44ODAzMjgsLTAuNDQxMTk5IC03Ljk1OTM0NywwLjA5MTgzIC0xMS45Mzk1MTYsMC44MzQxNTcgeiBtIDYuNzM2NjUzLDguODU1MjgzIGMgMS4zNTA4OTYsLTAuMDE5MDIgMS4yMzc3MzMsMC4wOTg0NSAyLjQ2OTc2OCwwLjIzNDk5MSAxLjM2NDkxNSwwLjg4OTQ1NCAwLjY4MzQ3MiwwLjIzNDA1NiAxLjg1NTM3MSwxLjMzMjkyMSAtMS4wMzI1NDcsMC41ODI5MzMgLTEuMTY3MDk2LDAuNTE2NTQ5IC0xLjkyNjU3MSwwLjg0NTIwMSAtMi4yNjM3MzcsMC4wOTc2MSAtMS42NTEyMDQsMC4wNTc5MyAtMy42MzU3NSwtMC4zMDgwMDEgLTEuNDczNDk5LC0wLjczNjg3OCAtMC4yNTk5NSwwLjA1NzI3IC0xLjc0NzYxMSwtMS4yMzU0MjQgMi44MTEyNjMsLTAuOTA0Mzk0IDEuMjkzNjI3LC0wLjU5Nzk2IDIuOTg0NzkzLC0wLjg2OTY4OCB6IgogICAgICAgICBzdHlsZT0ib3BhY2l0eToxO2ZpbGw6I2ZmYWEwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC41OTQ5MTY3NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2NjAiCiAgICAgICAgIGQ9Im0gMzcuNzcwNzU0LDEwMjguMjkzIGEgNS40OTI5ODUzLDQuMDI3OTE2MiA1LjMzMDU5OTQgMCAwIDEuOTM2NDE3LC0yLjcyOSIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC41OTQ5MTY3NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDY2MiIKICAgICAgICAgZD0ibSAzOS43MDcxNzEsMTAyNS41NjQgYSA1LjQ5MzI0NDgsNC4wMjgxMDY1IDUuMzMwNTk5NCAxIDAgLTEwLjkzODg5OCwtMS4wMjE1IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjU5NDkxNjc3O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0NjY0IgogICAgICAgICBkPSJtIDI4Ljc2ODI3MywxMDI0LjU0MjUgYSA1LjQ5Mjk4NTMsNC4wMjc5MTYyIDUuMzMwNTk5NCAwIDAgOS4wMDI0ODEsMy43NTA1IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjU5NDkxNjc3O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIgLz4KICAgICAgPGcKICAgICAgICAgaWQ9Imc0NjY2IgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgyLjY0NTk4NzMsMC4yNDY4ODYxOSwwLjI0Njg4NjE5LC0yLjY0NTk4NzMsLTM2OC44NjQ5MSwxMTE2LjY1NjMpIgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjIyMzg2NDk4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSI+CiAgICAgICAgPGVsbGlwc2UKICAgICAgICAgICBpZD0iZWxsaXBzZTQ2NjgiCiAgICAgICAgICAgcnk9IjIuMTA4MTkwMSIKICAgICAgICAgICByeD0iMi44NzUiCiAgICAgICAgICAgY3k9IjQ4LjU1OTUwMiIKICAgICAgICAgICBjeD0iMTQ3LjgyOCIKICAgICAgICAgICBzdHlsZT0ic3Ryb2tlLXdpZHRoOjAuMjIzODY0OTg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiIC8+CiAgICAgIDwvZz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0NjcwIgogICAgICAgICBkPSJtIDM3Ljk1MDExNiwxMDI4LjE4MzMgYSA1LjQ5Mjk4NTMsNC4wMjc5MTYyIDUuMzMwNTk5NCAwIDAgLTcuOTM4ODUxLC0wLjc0MDUiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2NzIiCiAgICAgICAgIGQ9Im0gNDEuMTA5ODk1LDEwMzAuOTMxMiBhIDEwLjYyOTkyMSw3Ljc5NDc2MTYgNS4zMzA1OTk0IDAgMCAzLjE0MDc4OCwtMy4xODIiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2NzQiCiAgICAgICAgIGQ9Im0gMzYuMTM3NjQzLDEwMzIuNDMzMyBhIDEwLjYyOTkyMSw3Ljc5NDc2MTYgNS4zMzA1OTk0IDAgMCA0Ljk3MjI1MiwtMS41MDIxIgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjU5NDkxNjc3O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0Njc2IgogICAgICAgICBkPSJtIDQ0LjI1MDY4MywxMDI3Ljc0OTIgYSAxMC42Mjk5MjEsNy43OTQ3NjE2IDUuMzMwNTk5NCAwIDAgLTEuODYyODU4LC03Ljc2ODEiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2NzgiCiAgICAgICAgIGQ9Im0gMjYuMTYxNzQ1LDEwMjkuMzQ5MiBhIDEwLjYyOTkyMSw3Ljc5NDc2MTYgNS4zMzA1OTk0IDAgMCA5Ljk3NTg5OCwzLjA4NDEiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2ODAiCiAgICAgICAgIGQ9Im0gNDIuMzg3ODI1LDEwMTkuOTgxMSBhIDEwLjYyOTkyMSw3Ljc5NDc2MTYgNS4zMzA1OTk0IDAgMCAtOS45NzY5OTcsLTMuMDg2NiIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC41OTQ5MTY3NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDY4MiIKICAgICAgICAgZD0ibSAyNC4yOTc3ODksMTAyMS41Nzg2IGEgMTAuNjI5OTIxLDcuNzk0NzYxNiA1LjMzMDU5OTQgMCAwIDEuODYzOTU2LDcuNzcwNiIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC41OTQ5MTY3NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDY4NCIKICAgICAgICAgZD0ibSAzMi40MTA4MjgsMTAxNi44OTQ1IGEgMTAuNjI5OTIxLDcuNzk0NzYxNiA1LjMzMDU5OTQgMCAwIC04LjExMzAzOSw0LjY4NDEiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2ODYiCiAgICAgICAgIGQ9Im0gNDQuMjUwNjgzLDEwMjcuNzQ5MiAtMC4xNDE3MzIsMC4yODQ2IC0wLjE0Mjc5NiwwLjI4OCAtMC4xNDMxNDksMC4yOTQ1IC0wLjE0NDU2NywwLjI5ODMgLTAuMTQ0NTY3LDAuMzA3MiAtMC4xNDcwNDcsMC4zMTE5IC0wLjE0OTg4MiwwLjMxNjcgLTAuMTUwNTkxLDAuMzI2NCAtMC4xNTI3MTYsMC4zMzM3IC0wLjE1NDQ4OSwwLjM0NDEgLTAuMTU3Njc3LDAuMzUxOSAtMC4xNjEyMiwwLjM2IC0wLjE2NDA1NSwwLjM3MSAtMC4xNjcyNDUsMC4zODE4IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjU5NDkxNjc3O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0Njg4IgogICAgICAgICBkPSJtIDQyLjEyODMxMywxMDMyLjMxOTQgLTAuNDYzNSwtMC4wMTggLTAuNDU0ODksLTAuMDE0IC0wLjQ0NzIzNiwtMC4wMSAtMC40NDExNDIsLTAuMDEgLTAuNDM1NDcyLDAgLTAuNDI5NDE0LDAgLTAuNDI0NzAxLDAuMDEgLTAuNDE5NTYzLDAuMDExIC0wLjQxNzI5NSwwLjAxNCAtMC40MTU1MjQsMC4wMTQgLTAuNDExNzY3LDAuMDIxIC0wLjQxMTEzLDAuMDI1IC0wLjQwOTM5NCwwLjAzMiAtMC40MDk2NDIsMC4wMzUiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2OTAiCiAgICAgICAgIGQ9Im0gNDYuMjk0MjUsMTAyNC4wMTYzIC0wLjE1NTkwNiwwLjI2NDcgLTAuMTU0NDg4LDAuMjYxMiAtMC4xNTEyOTksMC4yNjIyIC0wLjE0OTUyOCwwLjI2MTEgLTAuMTQ2NjkzLDAuMjYyOSAtMC4xNDc0MDEsMC4yNjAxIC0wLjE0Mzg1OSwwLjI2NDMgLTAuMTQzODU4LDAuMjY0IC0wLjE0MzUwNCwwLjI2NCAtMC4xNDEzNzgsMC4yNjg5IC0wLjE0MjA4NiwwLjI2OTMgLTAuMTQwMzE1LDAuMjc0MyAtMC4xNDIwODcsMC4yNzUzIC0wLjE0MDY2OSwwLjI4MDYiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2OTIiCiAgICAgICAgIGQ9Im0gNDIuMzg3ODI1LDEwMTkuOTgxMSAwLjI2Nzg3NCwwLjI0NzMgMC4yNjg1ODIsMC4yNTMgMC4yNjc4NzQsMC4yNTY1IDAuMjY4OTM3LDAuMjYyMiAwLjI3MTQxOCwwLjI3IDAuMjcyODM0LDAuMjc1MyAwLjI3Mzg5OCwwLjI4MDcgMC4yNzY3MzIsMC4yODgxIDAuMjc5NTY3LDAuMjk1OCAwLjI4MzExLDAuMzAzIDAuMjg3MzYyLDAuMzEyOCAwLjI5MDkwNiwwLjMyIDAuMjk2OTI5LDAuMzMxNyAwLjMwMDQ3MywwLjMzOTEiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ2OTQiCiAgICAgICAgIGQ9Im0gMzAuMDY4MTM1LDEwMzMuMzg0NSAtMC4zMDA0NzIsLTAuMzM5MSAtMC4yOTY5MjksLTAuMzMxNyAtMC4yOTA5MDYsLTAuMzE5OSAtMC4yODczNjIsLTAuMzEyOSAtMC4yODMxMSwtMC4zMDI5IC0wLjI3OTU2NywtMC4yOTU5IC0wLjI3NjczMywtMC4yODgxIC0wLjI3Mzg5NywtMC4yODA2IC0wLjI3MjgzNSwtMC4yNzUzIC0wLjI3MTA2MywtMC4yNyAtMC4yNjg5MzcsLTAuMjYxOSAtMC4yNjc4NzQsLTAuMjU2NSAtMC4yNjg1ODIsLTAuMjUzIC0wLjI2Nzg3NSwtMC4yNDczIgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjU5NDkxNjc3O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0Njk2IgogICAgICAgICBkPSJtIDM2LjEzNzY0MywxMDMyLjQzMzMgLTAuNDEwNjY5LDAuMDM4IC0wLjQxMDQ5MiwwLjA0NCAtMC40MTM1MDQsMC4wNDUgLTAuNDE0NTMxLDAuMDUyIC0wLjQxODQ2NSwwLjA1NSAtMC40MjA2MjYsMC4wNjIgLTAuNDI1OTA2LDAuMDY1IC0wLjQzMTQzMywwLjA2OCAtMC40MzUwMTEsMC4wNzYgLTAuNDQzMTk3LDAuMDc4IC0wLjQ0OTI5MiwwLjA4NCAtMC40NTcyOTksMC4wODkgLTAuNDY0MjgsMC4wOTYgLTAuNDc0ODAzLDAuMDk5IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjU5NDkxNjc3O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0Njk4IgogICAgICAgICBkPSJtIDM4LjQwMTUzMywxMDE2Ljc4MDYgMC4zMTE4MTEsMC4yMjE4IDAuMzA2MTQyLDAuMjIyMiAwLjMwMDgyNywwLjIyMjEgMC4yOTU1MTEsMC4yMjIyIDAuMjkwNTUyLDAuMjIxOCAwLjI4NzAwOCwwLjIyMzkgMC4yODM0NjQsMC4yMjYxIDAuMjc5MjEzLDAuMjI1NCAwLjI3NzQ0MSwwLjIyOTYgMC4yNzMxODksMC4yMjg5IDAuMjcyODM0LDAuMjM1MiAwLjI3MDM1NSwwLjIzNjcgMC4yNjkyOTEsMC4yNDAzIDAuMjY4NTgzLDAuMjQzNyIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC41OTQ5MTY3NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDcwMCIKICAgICAgICAgZD0ibSAzMi40MTA4MjgsMTAxNi44OTQ1IDAuNDA5Njc4LC0wLjAzNSAwLjQxMDc0LC0wLjAyOCAwLjQwOTc4MywtMC4wMjggMC40MTMwNzksLTAuMDIxIDAuNDE0MjEzLC0wLjAxOCAwLjQxNzI5NSwtMC4wMTQgMC40MjA4NzQsLTAuMDExIDAuNDI0NzAxLC0wLjAxIDAuNDI5NDEzLDAgMC40MzQxNjEsMTBlLTQgMC40NDExNDIsMC4wMSAwLjQ0NzIzNiwwLjAxIDAuNDU0ODksMC4wMTQgMC40NjM1LDAuMDE4IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjU5NDkxNjc3O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGg0NzAyIgogICAgICAgICBkPSJtIDIyLjE3NTQxOSwxMDI2LjE0ODcgMC4xNjcyNDQsLTAuMzgxOCAwLjE2NDA1NSwtMC4zNzEgMC4xNjEyMiwtMC4zNiAwLjE1NzY3OCwtMC4zNTE5IDAuMTU1OTA1LC0wLjM0MTYgMC4xNTMwNzEsLTAuMzMzNyAwLjE1MDU5LC0wLjMyNjQgMC4xNDg4MTksLTAuMzE5MiAwLjE0NzA0OCwtMC4zMTE5IDAuMTQ1NjMsLTAuMzA1IDAuMTQzNTAzLC0wLjMwMDUgMC4xNDQ1NjcsLTAuMjkyIDAuMTQxNzMzLC0wLjI5MDUgMC4xNDE3MzIsLTAuMjg0NSIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC41OTQ5MTY3NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDcwNCIKICAgICAgICAgZD0ibSAyNi4xNjE3NDUsMTAyOS4zNDkyIC0wLjI2ODU4MiwtMC4yNDM4IC0wLjI2OTI5MiwtMC4yNDAyIC0wLjI3MDM1NCwtMC4yMzY3IC0wLjI3MjgzNSwtMC4yMzUzIC0wLjI3MzE4OSwtMC4yMjg5IC0wLjI3NzQ0LC0wLjIyOTYgLTAuMjc4ODU5LC0wLjIyNTMgLTAuMjgzNDY0LC0wLjIyNjEgLTAuMjg3MDA4LC0wLjIyMzkgLTAuMjkwNTUxLC0wLjIyMTggLTAuMjk1NTEyLC0wLjIyMjIgLTAuMzAwODI3LC0wLjIyMjIgLTAuMzA2NDk2LC0wLjIyMjEgLTAuMzExODExLC0wLjIyMTgiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3MDYiCiAgICAgICAgIGQ9Im0gMjYuMzQyNjY3LDEwMTcuODQ4IDAuNDczNDkyLC0wLjEwMTMgMC40NjU4MzgsLTAuMDk0IDAuNDU3MDg3LC0wLjA4OSAwLjQ0OTI1NiwtMC4wODQgMC40NDE4ODYsLTAuMDggMC40MzYzMjMsLTAuMDc0IDAuNDMwMTIyLC0wLjA3IDAuNDI1OTA1LC0wLjA2NSAwLjQyMTkzNywtMC4wNTkgMC40MTcxMTgsLTAuMDU3IDAuNDE1ODc5LC0wLjA1IDAuNDEyNDA1LC0wLjA0OCAwLjQxMTYyNiwtMC4wNDEgMC40MDkyODcsLTAuMDQiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3MDgiCiAgICAgICAgIGQ9Im0gMjQuMjk3Nzg5LDEwMjEuNTc4NiAwLjE0MjQ0MSwtMC4yNzg1IDAuMTQwNjY5LC0wLjI3NzQgMC4xNDE3MzIsLTAuMjcyMiAwLjE0MDY3LC0wLjI3MTcgMC4xNDI0NDEsLTAuMjY2NSAwLjE0MjQ0LC0wLjI2NjQgMC4xNDM4NTksLTAuMjY0IDAuMTQ1Mjc1LC0wLjI2MTkgMC4xNDU5ODUsLTAuMjYyMiAwLjE0ODExLC0wLjI2MDQgMC4xNDk1MjcsLTAuMjYxMSAwLjE1MTMsLTAuMjYyMyAwLjE1MzQyNSwtMC4yNjMyIDAuMTU2OTY4LC0wLjI2MjYiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3MTAiCiAgICAgICAgIGQ9Im0gNDEuNjE4OTYyLDEwMzcuNzc3OSAwLjE1NTU1MSwtMC4yNjQ3IDAuMTU0ODQzLC0wLjI2MTIgMC4xNTEyOTksLTAuMjYyMiAwLjE0OTUyOCwtMC4yNjExIDAuMTQ4NDY0LC0wLjI2MDggMC4xNDU5ODUsLTAuMjYyMiAwLjE0Mzg1OCwtMC4yNjQgMC4xNDM4NTgsLTAuMjYzOSAwLjE0MzUwNCwtMC4yNjQgMC4xNDEzNzgsLTAuMjY5IDAuMTQyMDg3LC0wLjI2OTMgMC4xNDE3MzIsLTAuMjcyMSAwLjE0MDY2OSwtMC4yNzc0IDAuMTQxMDI0LC0wLjI4MSIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC41OTQ5MTY3NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDcxMiIKICAgICAgICAgZD0ibSA0My42NjI1MjksMTAzNC4wNDUgMC4xNDE3MzMsLTAuMjg0NiAwLjE0Mjc5NSwtMC4yODggMC4xNDMxNDksLTAuMjk0NSAwLjE0NDkyMiwtMC4yOTgzIDAuMTQ1NjMsLTAuMzA1MSAwLjE0NzA0NywtMC4zMTE4IDAuMTQ4NDY0LC0wLjMxODkgMC4xNTA1OTEsLTAuMzI2NCAwLjE1MzA3MSwtMC4zMzM3IDAuMTU0NDg4LC0wLjM0MzcgMC4xNTkwOTQsLTAuMzQ5OCAwLjE2MDE1OCwtMC4zNjI0IDAuMTY0MDU1LC0wLjM3MDkgMC4xNjcyNDQsLTAuMzgyIgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjU5NDkxNjc3O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgZD0ibSA0NS43ODQ4OTksMTAyOS40NzQ4IDAuNTA5MzUxLC01LjQ1ODUiCiAgICAgICAgIGlkPSIyNzEiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBkPSJtIDQxLjYxODk2MiwxMDM3Ljc3NzkgMC41MDkzNTEsLTUuNDU4NSIKICAgICAgICAgaWQ9IjI3MiIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC41OTQ5MTY3NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDcxNiIKICAgICAgICAgZD0ibSAyOS41NTg3ODUsMTAzOC44NDMgMC40NjMyNTIsMC4wMTggMC40NTUxMzgsMC4wMTQgMC40NDgzMzQsMC4wMTEgMC40Mzk3OTYsMCAwLjQzNTcyLDAgMC40MjkyMDEsMCAwLjQyNDkxMywtMC4wMSAwLjQyMDY2MiwtMC4wMTEgMC40MTcyOTUsLTAuMDE0IDAuNDE0NDI1LC0wLjAxOCAwLjQxMTc2OCwtMC4wMjEgMC40MTA4ODIsLTAuMDI1IDAuNDA5NjQyLC0wLjAzMiAwLjQwOTY0MSwtMC4wMzUiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3MTgiCiAgICAgICAgIGQ9Im0gMzUuNTQ5NDU0LDEwMzguNzI5IDAuNDEwNDIyLC0wLjAzOCAwLjQxMTgzOCwtMC4wNDEgMC40MTIxOTMsLTAuMDQ4IDAuNDE0NTMyLC0wLjA1MiAwLjQxODY3NywtMC4wNTUgMC40MjA2MjYsLTAuMDYyIDAuNDI1NjU3LC0wLjA2NSAwLjQzMTY4MSwtMC4wNjggMC40MzYzMjMsLTAuMDc0IDAuNDQxODg2LC0wLjA4IDAuNDQ5MjkxLC0wLjA4NCAwLjQ1NzA4NywtMC4wODkgMC40NjQyNDQsLTAuMDk2IDAuNDc1MDUxLC0wLjA5OSIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC41OTQ5MTY3NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Im0gMjkuNTU4Nzg1LDEwMzguODQzIDAuNTA5MzUsLTUuNDU4NSIKICAgICAgICAgaWQ9IjI3NSIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC41OTQ5MTY3NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoNDcyMSIKICAgICAgICAgZD0ibSAyMS42NjYwNjgsMTAzMS42MDczIDAuMzAxNTM2LDAuMzQxMiAwLjI5NTg2NiwwLjMyOTUgMC4yOTE5NjgsMC4zMjI1IDAuMjg2MywwLjMxMDQgMC4yODQxNzMsMC4zMDU0IDAuMjc5OTIxLDAuMjk1NSAwLjI3NjczMiwwLjI4ODEgMC4yNzM4OTgsMC4yODA2IDAuMjcyODM1LDAuMjc1MyAwLjI3LDAuMjY3NSAwLjI3LDAuMjY0NCAwLjI2Nzg3NCwwLjI1NjUgMC4yNjg1ODIsMC4yNTMgMC4yNjc1MiwwLjI0NzciCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjAuNTk0OTE2Nzc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDQ3MjMiCiAgICAgICAgIGQ9Im0gMjUuNTczNTU2LDEwMzUuNjQ0OSAwLjI2ODU4MywwLjI0MzggMC4yNjkyOTEsMC4yNDAzIDAuMjcwNzA5LDAuMjM2MyAwLjI3MTc3MiwwLjIzMjggMC4yNzQyNTIsMC4yMzE0IDAuMjc3NDQxLDAuMjI5NiAwLjI3ODg1OCwwLjIyNTcgMC4yODI0MDIsMC4yMjM2IDAuMjg2NjUzLDAuMjIzOSAwLjI5MTk2OSwwLjIyNDMgMC4yOTU4NjYsMC4yMjIyIDAuMjk5NDA5LDAuMjIgMC4zMDY0OTYsMC4yMjIyIDAuMzExODExLDAuMjIxOCIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MC41OTQ5MTY3NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Im0gMjEuNjY2MDY4LDEwMzEuNjA3MyAwLjUwOTM1MSwtNS40NTg2IgogICAgICAgICBpZD0iMjc4IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDowLjU5NDkxNjc3O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIgLz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=
"""
-materials_b64=\
-"""
+materials_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI5MDEiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9Ik1hdGVyaWFscy5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiCiAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvUGFydERlc2lnbl9Hcm9vdmUucG5nIgogICBpbmtzY2FwZTpleHBvcnQteGRwaT0iOTAiCiAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI5MCI+CiAgPGRlZnMKICAgICBpZD0iZGVmczI5MDMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTM3Ij4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzOTM5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmEzMDA7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZjAwO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwLjQzODYxOCIKICAgICAgICAgaWQ9InN0b3AzOTQxIiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM5NDMiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzdmNTEwMDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTA1Ij4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzOTA3IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmEzMDA7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZjAwO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwLjQ1NzcwMzY4IgogICAgICAgICBpZD0ic3RvcDM5MDkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzkxMSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojY2M4MDAwO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZhMzAwO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzkwMSIKICAgICAgICAgb2Zmc2V0PSIwLjQwNDc3MTgzIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZjAwO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzdmNTEwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzOTAzIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2NSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZhMzAwO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmYwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMC41MzE2MDIzOCIKICAgICAgICAgaWQ9InN0b3AzODY3IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4NjkiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzdmNTEwMDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODMwIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODMyIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmEzMDA7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZjAwO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwLjY0MTM0MDE0IgogICAgICAgICBpZD0ic3RvcDM4MzQiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzgzNiIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojY2M4MDAwO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQyMzciPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDQyMzkiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2Y4MmIzOTtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wNDI0MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNTIwMDAxO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNTIiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDA5MGZmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQwNTQiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wNDA2MCIKICAgICAgICAgb2Zmc2V0PSIwLjUiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmMGYxZjE7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDA0NmZmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDQwNTYiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDQ0Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwOTBmZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A0MDQ2IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDYxYWZmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDQwNDgiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMjczIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMjc1IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNjOGUwZjk7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMyNzciCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2Y3ZjlmYTtzdG9wLW9wYWNpdHk6MC4wOTY0OTEyMzsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzc3Ij4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMzc5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNjOGUwZjk7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMzODEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMjc5NTtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjY0IDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjMyIDogMjEuMzMzMzMzIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI5MDkiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTM2NzQiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMC41IDogMC4zMzMzMzMzMyA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF96PSIxIDogMC41IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAwLjUgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDA0NCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNTAiCiAgICAgICB4MT0iNDQuODU4MjE1IgogICAgICAgeTE9IjE0LjAxNjEyMyIKICAgICAgIHgyPSIzMy45Mjg2ODQiCiAgICAgICB5Mj0iMzMuMjE2MjUxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTc2ODAyMzcsMCwwLDAuOTYwMDM1MDgsMS40Njk0MzE5LDAuMTI3NjU3NjUpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0MDUyIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDA1OCIKICAgICAgIHgxPSI0Mi4zNzM3MDciCiAgICAgICB5MT0iNS43OTc0OTg3IgogICAgICAgeDI9IjUyLjMyMzIxOSIKICAgICAgIHkyPSIyMi42NzU4MjEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45NzY4MDIzNywwLDAsMC45NjAwMzUwOCwxLjQ2OTQzMTksMC4xMjc2NTc2NSkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQwNTItMSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNTgtNiIKICAgICAgIHgxPSI0Mi4zNzM3MDciCiAgICAgICB5MT0iNS43OTc0OTg3IgogICAgICAgeDI9IjUyLjMyMzIxOSIKICAgICAgIHkyPSIyMi42NzU4MjEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45NzY4MDIzNywwLDAsMC45NjAwMzUwOCwxLjQ2OTQzMTksMC4xMjc2NTc2NSkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNTItMSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmEzMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNDA1NC01IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDQwNjAtOCIKICAgICAgICAgb2Zmc2V0PSIwLjUiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmMDA7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojY2M4MDAwO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDQwNTYtNCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTMwLjI5NTIyNSwtMi45Mjg3MTQ3KSIKICAgICAgIHkyPSIyMi42NzU4MjEiCiAgICAgICB4Mj0iNTIuMzIzMjE5IgogICAgICAgeTE9IjUuNzk3NDk4NyIKICAgICAgIHgxPSI0Mi4zNzM3MDciCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNzgiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0MDUyLTEiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQwNDQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODg1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTc2ODAyMzcsMCwwLDAuOTYwMDM1MDgsMTA3LjEwNTc5LC0yMi4yMzU5NzgpIgogICAgICAgeDE9IjQ0Ljg1ODIxNSIKICAgICAgIHkxPSIxNC4wMTYxMjMiCiAgICAgICB4Mj0iMzMuOTI4Njg0IgogICAgICAgeTI9IjMzLjIxNjI1MSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDA1Mi0xIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5MCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk3NjgwMjM3LDAsMCwwLjk2MDAzNTA4LDEwNy4xMDU3OSwtMjIuMjM1OTc4KSIKICAgICAgIHgxPSI0Mi4zNzM3MDciCiAgICAgICB5MT0iNS43OTc0OTg3IgogICAgICAgeDI9IjUyLjMyMzIxOSIKICAgICAgIHkyPSIyMi42NzU4MjEiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQwNTIiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODkzIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTc2ODAyMzcsMCwwLDAuOTYwMDM1MDgsMTA3LjEwNTc5LC0yMi4yMzU5NzgpIgogICAgICAgeDE9IjQyLjM3MzcwNyIKICAgICAgIHkxPSI1Ljc5NzQ5ODciCiAgICAgICB4Mj0iNTIuMzIzMjE5IgogICAgICAgeTI9IjIyLjY3NTgyMSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDA1Mi0xLTAiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDA5MGZmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQwNTQtNS01IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDQwNjAtOC02IgogICAgICAgICBvZmZzZXQ9IjAuNSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2YwZjFmMTtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDQ2ZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDA1Ni00LTYiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMjIuNjc1ODIxIgogICAgICAgeDI9IjUyLjMyMzIxOSIKICAgICAgIHkxPSI1Ljc5NzQ5ODciCiAgICAgICB4MT0iNDIuMzczNzA3IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk3NjgwMjM3LDAsMCwwLjk2MDAzNTA4LC0zLjM2MzAxOTksLTE4LjMyMjk4MikiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5MTIiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0MDUyLTEtMCIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDA1Mi0xLTAtMCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDkwZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNDA1NC01LTUtOSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3A0MDYwLTgtNi04IgogICAgICAgICBvZmZzZXQ9IjAuNSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2YwZjFmMTtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDQ2ZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDA1Ni00LTYtNCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIHkyPSIyMi42NzU4MjEiCiAgICAgICB4Mj0iNTIuMzIzMjE5IgogICAgICAgeTE9IjUuNzk3NDk4NyIKICAgICAgIHgxPSI0Mi4zNzM3MDciCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTc2ODAyMzcsMCwwLDAuOTYwMDM1MDgsMTI2LjczNzY5LC03MC4wOTI2ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTg1IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDA1Mi0xLTAtMCIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDA0NC04Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwOTBmZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A0MDQ2LTIiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwNjFhZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDA0OC0xIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjMzLjIxNjI1MSIKICAgICAgIHgyPSIzMy45Mjg2ODQiCiAgICAgICB5MT0iMTQuMDE2MTIzIgogICAgICAgeDE9IjQ0Ljg1ODIxNSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45NzY4MDIzNywwLDAsMC45NjAwMzUwOCwtMjYuMjQ2NzcsLTguNDYwNzU5NSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNzIiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0MDQ0LTgiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQwNDQtOC00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg4NS02LTUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45NzY4MDIzNywwLDAsMC45NjAwMzUwOCw1OC4zMDczNjcsNTQuNjcxNDY5KSIKICAgICAgIHgxPSI0NC44NTgyMTUiCiAgICAgICB5MT0iMTQuMDE2MTIzIgogICAgICAgeDI9IjMzLjkyODY4NCIKICAgICAgIHkyPSIzMy4yMTYyNTEiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNDQtOC00Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwOTBmZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A0MDQ2LTItMCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzA2MWFmZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A0MDQ4LTEtOSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIHkyPSIzMy4yMTYyNTEiCiAgICAgICB4Mj0iMzMuOTI4Njg0IgogICAgICAgeTE9IjE0LjAxNjEyMyIKICAgICAgIHgxPSI0NC44NTgyMTUiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTc2ODAyMzcsMCwwLDAuOTYwMDM1MDgsMTQ1LjQxMjk5LDk0Ljc4MjIyMSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQxNjMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0MDQ0LTgtNCIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDA1Mi0xLTAtOSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDkwZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNDA1NC01LTUtMiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3A0MDYwLTgtNi01IgogICAgICAgICBvZmZzZXQ9IjAuNSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2YwZjFmMTtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDQ2ZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDA1Ni00LTYtNSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIHkyPSIyMi42NzU4MjEiCiAgICAgICB4Mj0iNTIuMzIzMjE5IgogICAgICAgeTE9IjUuNzk3NDk4NyIKICAgICAgIHgxPSI0Mi4zNzM3MDciCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTc2ODAyMzcsMCwwLDAuOTYwMDM1MDgsMTI2LjczNzY5LC03MC4wOTI2ODcpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MjE3IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDA1Mi0xLTAtOSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDA1Mi0xLTA1IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5MC0zLTUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC41NTM3MDYzOCwwLDAsMC41NTM2NDMzMSw3OC43OTQ0MzksLTI2LjE3OTg3OCkiCiAgICAgICB4MT0iNDIuMzczNzA3IgogICAgICAgeTE9IjUuNzk3NDk4NyIKICAgICAgIHgyPSI1Mi4zMjMyMTkiCiAgICAgICB5Mj0iMjIuNjc1ODIxIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDUyLTEtMDUiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZhMzAwO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQwNTQtNS0xIiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDQwNjAtOC04IgogICAgICAgICBvZmZzZXQ9IjAuNSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmYwMDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNjYzgwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDA1Ni00LTEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iODYuMTkxOTc4IgogICAgICAgeDI9Ii01OC45MTA4MTIiCiAgICAgICB5MT0iNzEuODY4MDI3IgogICAgICAgeDE9Ii02OS4yMDIyNzEiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNTUzNzA2MzgsMCwwLDAuNTUzNjQzMzEsNjMuNzgxMjI2LC05LjM3ODA3MjIpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDU1IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzkwNSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDA1Mi0xIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDA1MyIKICAgICAgIHgxPSItODUuNjQwNjMzIgogICAgICAgeTE9IjU0LjYwNDQyNCIKICAgICAgIHgyPSItMzcuNjMyMTI2IgogICAgICAgeTI9IjU0LjYwNDQyNCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0MDUyLTEiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDU3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iLTg1LjY0MDYzMyIKICAgICAgIHkxPSI1NC42MDQ0MjQiCiAgICAgICB4Mj0iLTM3LjYzMjEyNiIKICAgICAgIHkyPSI1NC42MDQ0MjQiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQwNTItMSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNjQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSItODUuNjQwNjMzIgogICAgICAgeTE9IjU0LjYwNDQyNCIKICAgICAgIHgyPSItMzcuNjMyMTI2IgogICAgICAgeTI9IjU0LjYwNDQyNCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDA1Mi0xIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDA2NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9Ii04NS42NDA2MzMiCiAgICAgICB5MT0iNTQuNjA0NDI0IgogICAgICAgeDI9Ii0zNy42MzIxMjYiCiAgICAgICB5Mj0iNTQuNjA0NDI0IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODMwIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgyOCIKICAgICAgIHgxPSI0OC43Mzg4MzQiCiAgICAgICB5MT0iNi44OTk3NTQiCiAgICAgICB4Mj0iNTYuOTQwNzAxIgogICAgICAgeTI9IjE5LjI0Mzg5MyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMjIuNjc1ODIxIgogICAgICAgeDI9IjUyLjMyMzIxOSIKICAgICAgIHkxPSI1Ljc5NzQ5ODciCiAgICAgICB4MT0iNDIuMzczNzA3IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjU1MzcwNjM4LDAsMCwwLjU1MzY0MzMxLDYzLjc4MTIyNiwtOS4zNzgwNzIyKSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA1NS0zIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDA1Mi0xLTA1LTUiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwNTItMS0wNS01Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmYTMwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A0MDU0LTUtMS04IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDQwNjAtOC04LTAiCiAgICAgICAgIG9mZnNldD0iMC41IgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZjAwO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzdmNTEwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A0MDU2LTQtMS0xIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjIyLjY3NTgyMSIKICAgICAgIHgyPSI1Mi4zMjMyMTkiCiAgICAgICB5MT0iNS43OTc0OTg3IgogICAgICAgeDE9IjQyLjM3MzcwNyIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuNDQ3NjE3MTIsLTAuMDM5NzQ2MjQsMC4wMzk2ODU3MiwtMC40NDgxOTc2OSwtNDQuMzQ3NjIyLDkwLjg0MjQzOSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNzQiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODYzIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk3IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NSIKICAgICAgIHgxPSItMTMuMDU0MjA5IgogICAgICAgeTE9IjU1LjMxMjE5NSIKICAgICAgIHgyPSItMTIuOTE1OTQiCiAgICAgICB5Mj0iNDEuNTMwNzU0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM5MzciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTM1IgogICAgICAgeDE9IjE3LjYwMzY2OCIKICAgICAgIHkxPSI0OC40MzgzMTYiCiAgICAgICB4Mj0iMTMuODc0NjE3IgogICAgICAgeTI9IjQzLjA5MDI3NSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzOTM3IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg4MiIKICAgICAgIHgxPSItMTMuMjIxNTUiCiAgICAgICB5MT0iNTQuODEzMjQ4IgogICAgICAgeDI9Ii0xMy41MDgwOTgiCiAgICAgICB5Mj0iNDAuOTQ1NTcyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4wNDM0NzgzLDAsMCwxLjA0MzQ3ODMsLTQxLjk1MDE3NiwtMTE0LjU2OTQ3KSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDEyNTEyIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50Mjc4IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBjeD0iNTUiCiAgICAgICBjeT0iMTI1IgogICAgICAgZng9IjU1IgogICAgICAgZnk9IjEyNSIKICAgICAgIHI9IjE0LjM3NSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MTI1MTIiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eToxLjAwMDAwMDA7IgogICAgICAgICBvZmZzZXQ9IjAuMDAwMDAwMCIKICAgICAgICAgaWQ9InN0b3AxMjUxMyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZjUyMDtzdG9wLW9wYWNpdHk6MC44OTEwODkwODsiCiAgICAgICAgIG9mZnNldD0iMC41MDAwMDAwMCIKICAgICAgICAgaWQ9InN0b3AxMjUxNyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZjMwMDtzdG9wLW9wYWNpdHk6MC4wMDAwMDAwOyIKICAgICAgICAgb2Zmc2V0PSIxLjAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wMTI1MTQiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6em9vbT0iOS42ODc1IgogICAgIGlua3NjYXBlOmN4PSIzMiIKICAgICBpbmtzY2FwZTpjeT0iMzIiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNTM2IgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjgwMSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6c25hcC1nbG9iYWw9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1ub2Rlcz0idHJ1ZSIKICAgICBpbmtzY2FwZTpvYmplY3QtcGF0aHM9InRydWUiCiAgICAgaW5rc2NhcGU6b2JqZWN0LW5vZGVzPSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtaW50ZXJzZWN0aW9uLXBhdGhzPSJ0cnVlIiAvPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTI5MDYiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIj4KICAgIDxnCiAgICAgICBpZD0iZzM4ODQiPgogICAgICA8cGF0aAogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjA4OTUyMjYsLTAuNzI4OTE3MDUsMC43MjcyNzIwNSwxLjA5MTk4NywyMy41NzYyNTEsLTM1Ljc5NzQ2OSkiCiAgICAgICAgIGQ9Im0gLTEuNTcwMDcyMiw0OC4xMjIyMzggYSAxMS41NDM1NDUsMTYuNzc3NzE2IDAgMSAxIC0yMy4wODcwODk4LDAgMTEuNTQzNTQ1LDE2Ljc3NzcxNiAwIDEgMSAyMy4wODcwODk4LDAgeiIKICAgICAgICAgc29kaXBvZGk6cnk9IjE2Ljc3NzcxNiIKICAgICAgICAgc29kaXBvZGk6cng9IjExLjU0MzU0NSIKICAgICAgICAgc29kaXBvZGk6Y3k9IjQ4LjEyMjIzOCIKICAgICAgICAgc29kaXBvZGk6Y3g9Ii0xMy4xMTM2MTciCiAgICAgICAgIGlkPSJwYXRoMzgxNS0yLTMiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmM3MDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiM1ZTM4MDA7c3Ryb2tlLXdpZHRoOjEuNTI1MDQ1MzM7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIiAvPgogICAgICA8cGF0aAogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjEzNTc3NTEsLTAuNzQ2Nzk3NzEsMC43NTgxNDYyNiwxLjExODc3MzksNi44NzkwMTAxLC0yNi43NTgzMTIpIgogICAgICAgICBkPSJtIC0xLjU3MDA3MjIsNDguMTIyMjM4IGEgMTEuNTQzNTQ1LDE2Ljc3NzcxNiAwIDEgMSAtMjMuMDg3MDg5OCwwIDExLjU0MzU0NSwxNi43Nzc3MTYgMCAxIDEgMjMuMDg3MDg5OCwwIHoiCiAgICAgICAgIHNvZGlwb2RpOnJ5PSIxNi43Nzc3MTYiCiAgICAgICAgIHNvZGlwb2RpOnJ4PSIxMS41NDM1NDUiCiAgICAgICAgIHNvZGlwb2RpOmN5PSI0OC4xMjIyMzgiCiAgICAgICAgIHNvZGlwb2RpOmN4PSItMTMuMTEzNjE3IgogICAgICAgICBpZD0icGF0aDM4MTUtMi0zLTgiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmM3MDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiM1ZTM4MDA7c3Ryb2tlLXdpZHRoOjEuNDc1NjgwMjc7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIiAvPgogICAgICA8cGF0aAogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNzY2NzY2MiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Im0gMTUuNzQ4NjIzLDE4LjEwMjM0MSBjIDYuMzI2NDU3LC0zLjkxNjU2MSAxNy42Nzc2NDIsLTEuODU3NTE5IDI1Ljk2MTQ0MywxMC4zNDM5NzMgNy41MzE0NDYsMTEuMDkzMzIzIDYuMjMzNDg3LDIyLjMzNTA5NyAtMC41MjE1MTgsMjcuMTk2OTY4IEwgNTYuNDg4NTkxLDQ0LjYzMTE3NiBDIDYzLjcwMzk0NywzOS4xNDk4NjUgNjMuMDgyMTY5LDI3LjkyMTc1OCA1Ni45ODM1NjQsMTguMDc3MzAxIDUwLjEwMTA0LDYuOTY3NDI2MSAzOC42MjYxNjEsNC4yMTIzNDU2IDMyLjA4NDY2NCw3Ljk4OTA4MDcgeiIKICAgICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzgyOCk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiM1ZTM4MDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIgogICAgICAgICBpZD0icGF0aDM4NDYtMyIgLz4KICAgICAgPHBhdGgKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC44MzEyNDkzMywtMC41MzU1MTAxNywwLjU1NDg3MDkxLDAuODAyMjQ1MSwxMi41MTUxODcsLTguNjk5MzEyOCkiCiAgICAgICAgIGQ9Im0gLTIuNDI4MDYzNCw0OC4xMjIyMzggYSAxMC42ODU1NTQsMTYuNzc3NzE2IDAgMSAxIC0yMS4zNzExMDY2LDAgMTAuNjg1NTU0LDE2Ljc3NzcxNiAwIDEgMSAyMS4zNzExMDY2LDAgeiIKICAgICAgICAgc29kaXBvZGk6cnk9IjE2Ljc3NzcxNiIKICAgICAgICAgc29kaXBvZGk6cng9IjEwLjY4NTU1NCIKICAgICAgICAgc29kaXBvZGk6Y3k9IjQ4LjEyMjIzOCIKICAgICAgICAgc29kaXBvZGk6Y3g9Ii0xMy4xMTM2MTciCiAgICAgICAgIGlkPSJwYXRoMzgxNSIKICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmYzcwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzVlMzgwMDtzdHJva2Utd2lkdGg6Mi4wMzY5OTcwODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICBzb2RpcG9kaTp0eXBlPSJhcmMiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGQ9Ik0gNy4wNjYzOTUxLDMxLjM5NDU1MiBDIDE3LjA2NjUyNywyNC43NTY5MjYgMzYuMzA2MTA4LDUxLjM3NDg0MyAyNS42OTU5NzYsNTkuMzAzNDM0IGwgMTEuOTI5NjIyLC04LjkxNDYwMiBjIDExLjY0MDc0NywtOC43NzY2MTYgLTcuMDU3MjgsLTM0LjIxMjEzIC0xOC42MTg5MzMsLTI2LjkxOTY4IHoiCiAgICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2ZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMwNTUpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojNWUzODAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIKICAgICAgICAgaWQ9InBhdGgzODQ2LTMtMyIgLz4KICAgICAgPHBhdGgKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC44MzE3MjQ3MiwtMC41NTUxODgyNCwwLjU1NTE4ODI0LDAuODMxNzI0NzIsMC41NzEyMDQxOSwtMS45NTU5ODgzKSIKICAgICAgICAgZD0ibSAtMi4yODQxMjE1LDQ4LjEyMjIzOCBhIDEwLjgyOTQ5NSwxNi43Nzc3MTYgMCAxIDEgLTIxLjY1ODk5MDUsMCAxMC44Mjk0OTUsMTYuNzc3NzE2IDAgMSAxIDIxLjY1ODk5MDUsMCB6IgogICAgICAgICBzb2RpcG9kaTpyeT0iMTYuNzc3NzE2IgogICAgICAgICBzb2RpcG9kaTpyeD0iMTAuODI5NDk1IgogICAgICAgICBzb2RpcG9kaTpjeT0iNDguMTIyMjM4IgogICAgICAgICBzb2RpcG9kaTpjeD0iLTEzLjExMzYxNyIKICAgICAgICAgaWQ9InBhdGgzODE1LTIiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmM3MDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiM1ZTM4MDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIiAvPgogICAgICA8cGF0aAogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjM3OTIzOTEsLTAuMjUzMTQ3NTYsMC4yNTMxNDc1NiwwLjM3OTIzOTEsOC44ODQ0NjE0LDI0LjMwNTQ4NikiCiAgICAgICAgIGQ9Im0gLTIuMjg0MTIxNSw0OC4xMjIyMzggYSAxMC44Mjk0OTUsMTYuNzc3NzE2IDAgMSAxIC0yMS42NTg5OTA1LDAgMTAuODI5NDk1LDE2Ljc3NzcxNiAwIDEgMSAyMS42NTg5OTA1LDAgeiIKICAgICAgICAgc29kaXBvZGk6cnk9IjE2Ljc3NzcxNiIKICAgICAgICAgc29kaXBvZGk6cng9IjEwLjgyOTQ5NSIKICAgICAgICAgc29kaXBvZGk6Y3k9IjQ4LjEyMjIzOCIKICAgICAgICAgc29kaXBvZGk6Y3g9Ii0xMy4xMTM2MTciCiAgICAgICAgIGlkPSJwYXRoMzgxNS0yLTIiCiAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzODgyKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzVlMzgwMDtzdHJva2Utd2lkdGg6NC4zODYyODE0OTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICBzb2RpcG9kaTp0eXBlPSJhcmMiIC8+CiAgICA8L2c+CiAgICA8Y2lyY2xlCiAgICAgICByPSIxNS4wMDAwMDEiCiAgICAgICBjeT0iMTUuODY1MzIiCiAgICAgICBjeD0iMTUuNDQxMTMiCiAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmJsb2NrO3Zpc2liaWxpdHk6dmlzaWJsZTtmaWxsOnVybCgjcmFkaWFsR3JhZGllbnQyNzgpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjMwNDM0ODExO21hcmtlcjpub25lIgogICAgICAgaWQ9InBhdGgxMjUxMSIKICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUvamltbWFjL3hpbWlhbl9hcnQvaWNvbnMvbmF1dGlsdXMvc3VzZTkzL3N0b2NrX25ldy0xNi5wbmciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iMzMuODUyMjAzIgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjMzLjg1MjIwMyIgLz4KICA8L2c+Cjwvc3ZnPgo=
"""
-fusion_b64=\
-"""
+fusion_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI1NjgiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMiAoNWMzZTgwZCwgMjAxNy0wOC0wNikiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImZ1c2lvbi5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMyNTcwIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgwNSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMzNDY1YTQ7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzgwNyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM0NjVhNDtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODA5IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2NCI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2NiIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODY4IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzU5MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNjOGUwZjk7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzU5NSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzYzN2RjYTtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNTk3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUyNTc2IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICByPSIxOS41NzE0MjgiCiAgICAgICBmeT0iMjYuMjgxNzQ0IgogICAgICAgZng9IjQ2LjUzNDEzNCIKICAgICAgIGN5PSIyNi4yODE3NDQiCiAgICAgICBjeD0iNDYuNTM0MTM0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMDkwIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzE0MyIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4xNDg2MDg4LDEuODQ3NzYxNywtMy4wNTY2NzMsMS45MDAwOTQsNzMuMjU3NzQ1LC0xMTIuMTAxNikiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNDMiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzE0NSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM0NjVhNDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDMxNDciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICByPSIxOS41NzE0MjgiCiAgICAgICBmeT0iMjUuMTQ5MDQyIgogICAgICAgZng9IjQ4LjY0NTgzNiIKICAgICAgIGN5PSIyNS4xNDkwNDIiCiAgICAgICBjeD0iNDguNjQ1ODM2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjYzMjk0MDI5LDAuOTMwODkxMzIsLTAuODI2OTUzNzYsMC41NjIyNzAwMiwzOC42NTMwMjIsLTM0LjI3NTQ5NikiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMxNjUiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMTQzLTciCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNDMtNyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMTQ1LTAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMTQ3LTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMTQzIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzAyMyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjE3NTE4MjMsMS44OTA1MTA0LC0zLjEyNzM5MDQsMS45NDQwNTM0LDYxLjUwNzE4MywtMTI1LjA2NjM3KSIKICAgICAgIGN4PSI0Ni41MzQxMzQiCiAgICAgICBjeT0iMjYuMjgxNzQ0IgogICAgICAgZng9IjQ2LjUzNDEzNCIKICAgICAgIGZ5PSIyNi4yODE3NDQiCiAgICAgICByPSIxOS41NzE0MjgiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4MDUiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzODExIgogICAgICAgY3g9IjIyLjYyNTU2MyIKICAgICAgIGN5PSIzMi44MjY2NjQiCiAgICAgICBmeD0iMjIuNjI1NTYzIgogICAgICAgZnk9IjMyLjgyNjY2NCIKICAgICAgIHI9IjEzIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjIyMTg4MDA0LC0wLjE2NjQxMDA0LDAuNjkyMzA3NjYsMC45MjMwNzY4OCw1LjAxMTQ4MzUsNS42OTUxMDU2KSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMTQzLTciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ4NjMiCiAgICAgICB4MT0iMS44MjYwOCIKICAgICAgIHkxPSIzMi4xNzM5MDgiCiAgICAgICB4Mj0iNjEuODI2MDgiCiAgICAgICB5Mj0iMzIuMTczOTA4IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI0LjcyMzIxNjEiCiAgICAgaW5rc2NhcGU6Y3g9Ii05MS42Nzk2NTEiCiAgICAgaW5rc2NhcGU6Y3k9IjE4LjA5NjAzNCIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjI1NjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTM2MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTkiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii05IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMjk5NiIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEyNTczIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZSAvPgogICAgICAgIDxkYzpjcmVhdG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W3dtYXllcl08L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnRpdGxlPlBhcnRfRnVzZTwvZGM6dGl0bGU+CiAgICAgICAgPGRjOmRhdGU+MjAxMS0xMC0xMDwvZGM6ZGF0ZT4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9QYXJ0L0d1aS9SZXNvdXJjZXMvaWNvbnMvUGFydF88L2RjOmlkZW50aWZpZXI+CiAgICAgICAgPGRjOnJpZ2h0cz4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkZyZWVDQUQgTEdQTDIrPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpyaWdodHM+CiAgICAgICAgPGNjOmxpY2Vuc2U+aHR0cHM6Ly93d3cuZ251Lm9yZy9jb3B5bGVmdC9sZXNzZXIuaHRtbDwvY2M6bGljZW5zZT4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bYWdyeXNvbl0gQWxleGFuZGVyIEdyeXNvbjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIj4KICAgIDxwYXRoCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6dXJsKCNsaW5lYXJHcmFkaWVudDg2Myk7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBkPSJtIDEuODI2MDgsMi4xNzM5MDcgdiA2MC4wMDAwMDEgaCA2MCBWIDIuMTczOTA3IFogTSA2LDYgSCA1OCBWIDU4IEggNiBaIgogICAgICAgaWQ9InJlY3QyMjMzIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtmaWxsOnVybCgjcmFkaWFsR3JhZGllbnQzMDIzKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MS45OTc4Mjg3MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyOm5vbmU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIKICAgICAgIGQ9Ik0gNDEsNiBDIDMyLjIyMzk4Niw2IDI0LjgzOTUyMywxMS45NDU0NDEgMjIuNjU2MjUsMjAuMDMxMjUgMTIuMzIzMzA1LDIwLjIxNzQwNiA0LDI4LjYyMjU5NCA0LDM5IDQsNDkuNDk0MDEgMTIuNTA1OTksNTggMjMsNTggMzEuNzc2MDE0LDU4IDM5LjE2MDQ3Nyw1Mi4wNTQ1NTkgNDEuMzQzNzUsNDMuOTY4NzUgNTEuNjc2Njk1LDQzLjc4MjU5NCA2MCwzNS4zNzc0MDYgNjAsMjUgNjAsMTQuNTA1OTkgNTEuNDk0MDEsNiA0MSw2IFoiCiAgICAgICBpZD0icGF0aDM1NTAtMyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6dXJsKCNyYWRpYWxHcmFkaWVudDM4MTEpO3N0cm9rZS13aWR0aDoxMDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgZD0ibSAyMi43NTc3OTYsMjMuMjMxNTIxIGMgNS43OTkzNywyLjYxNTQ2OSAxMC4yOTYyNTksNy42Mzg5MDMgMTYsMjAiCiAgICAgICBpZD0icGF0aDMwMjciCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTt2aXNpYmlsaXR5OnZpc2libGU7ZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoxLjk5NzgyODY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlcjpub25lO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiCiAgICAgICBkPSJNIDQxLDggQyAzMi42MTA5NDMsOCAyNS42NzEyMTksMTQuMDcxMDc2IDI0LjI4MTI1LDIyLjA2MjUgMjMuODU5NzA5LDIyLjAzMTE5OSAyMy40Mjk1NDEsMjIgMjMsMjIgMTMuNjEwNTU4LDIyIDYsMjkuNjEwNTYgNiwzOSA2LDQ4LjM4OTQ0IDEzLjYxMDU1OCw1NiAyMyw1NiAzMS4zODkwNTcsNTYgMzguMzI4NzgxLDQ5LjkyODkyNCAzOS43MTg3NSw0MS45Mzc1IDQwLjE0MDI5MSw0MS45Njg4MDEgNDAuNTcwNDU5LDQyIDQxLDQyIDUwLjM4OTQ0Miw0MiA1OCwzNC4zODk0NCA1OCwyNSA1OCwxNS42MTA1NiA1MC4zODk0NDIsOCA0MSw4IFoiCiAgICAgICBpZD0icGF0aDM1NTAtMy0xIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjYyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBpZD0icGF0aDMwNDIiCiAgICAgICBkPSJtIDQ5LjE5OTk4OCw5Ni43OTAyODcgNDcuNjIyNjk0LDAuMDQxOTIgLTAuMDgzODQsLTQ3LjA1NTEwOSIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjIuNjA4Njk1NzU7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgPC9nPgo8L3N2Zz4K
"""
-#new iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAPdEVYdEF1dGhvcgBbd21heWVyXauF7RsAAAAYdEVYdENyZWF0aW9uIFRpbWUAMjAxMS0xMC0xMEUb11UAABFMSURBVHic5Zt5kFxHfcc//a45dvbS7upYXSvJEkLYJLHlg8NBGCLANsRgMMQJBEjA2MQuCJAQKoQQSIWCkAKDw1EBAmXu4hDBBiJjSKi4JGwBNodkSawlI8s6VsfuzuzMvPe6f/mj5828N8dKPiQo6KqZ6dfT1/fbv1//fn08+B0P6i2f+vFarfgqxmAEjBHECCIGIwYREC0YBIxBC4g2CIIRQYzNY4yxzyKI0QiNciKN8hoRwAhabBtGNDTaNEgrv7H1ixG0ERCxfTG2fttHY+Mitk4jCKk8zTYMJqmj8Z82BoXave/2t17txbh5JfpcQQHSoCWJNiKNH/uvkM5KkpYuhgKRVhYFiP03UwzVSpG2lExXpK29TGOZrjafpWvWbJ2Al0rfoxy52sSNLErjKCCEsFFMOQYdJbUolFKoOCZKiiiFGypCYpvFARUpwkZ9KFCxwqAa+TUqtIU1CpwQFYFu1I9SqDhCATp5DsEltH1yFCpSKEJi1UAWKxwUkYpsG6FCoQDQTgixWgt8JQHdJEAh9X971caf8lseVl/+nsyz1y3TjR+/WySj0y3dTHSrpWempZc90hJdzNbVnmaoHD/M9KE9TB/ZR1SdIazOEtfnEDE4XoCf7yfoW0B+cDHFkeUU+pdgoFVnY57I9rE1L+zZ8hbVjrUrAWczRLUKB3fdxaHd2wmrsz3z6bCKDqvUZo4w8/AuAPx8PwPjGxhc9gc4udKjan9eAv79+ks6GHu8wtDQxFDoq39W8GogDzCydDUbLtrM0nVPptA3iOf7KMdFKYWIIY4i5manObx/Fzu3b+XQAz/n2OR2jk1ur4vIJ91c9PbZhx461t7Wuqv+tX0KbYZfiwQUR1e9IFJ8RMG4chw2PvulPOlpl5Mr9PUso5SDH+QYHFnI4MhC1p3/h9Sqc9y/43v88PZP50wcX2/C4JrS6MRflaf2feF0+3K2CXCLY6s+qOD1AE962hVccsXL8bygmUESfwQBQ9MXAUFhLY/jKjzHJV8o8ntPv4INF2/mnm9/jvt+sGVElPp8aXT1M8pTwzfBjqhHP5rh7BFwzjm54rS+VcGLc/k+Ln/NP7Jw+RqAptNjTEpSxaarxGo3SBFjkFioSYTnOQS+j+/7POX5f87aC57JNz/299Sr5df1jR1bUfHHX8LBg3Pzdcs5k5hTwe2b1l9X8OLS8BjXvu3jTfDGCEZbgKrhW1gfAU41AUWRplypUquFiMDo+Ar+5O8+xuDYUkBd3hflvgSb5h3ks0JA3+iqfwGeOzg6zjVvupkgXwAEra0ZVKoNfC/okv5IM16rR8xWqhgj5PIFXvyG9zM4Og5wRXF0383z9e2ME1AaW3UNijf7QY4X3fQ+/CCHCOjYAC3g9pMddYtPUrgly0HKtdaxZma2gtYGzw+46sb3kSv0oZS6vjq1p2f/zigBQ0MTQwK3AOrK172bIF9oLEZ0w5W2ok5Kz+3HxruNdisTTac/iWojTM9W0MaQLxS4/DXvAuDkL/8XE9fOPgGRp94GjG546vNYuMzqvNY6s2hpAU5/ktFtH/0u0tBGitHCzPQciLBw2QTnXvrHmLjGzIM/PLsE5JesWoniJqUUlzzv5Q3wiUlrrfAyoNPgM2nt0jH/f1GsKc/VAbhw88twPI/q4Z0URpYtPWsEOJG8Eshd8Jxr8XN5q/fapEYtO/JGukjBaYDtJR3lSg2tDUEux/mb/xQRjeN4rz9rBCilrgXYcNFmAGKtW6OOdII3kll8dQOfYS8JXeaHpMxspQrAEzdelsB9hegwg/nxcIRUcWzl7yvlPAvkfEQ9EVgIjA+MLqFQ6re6GRu7T9LsvJ3v0xsiFkM7SelJsTHSp5COJFKdCxnoL1Is9bNwxXqOPLhr6ez+bRtKqy997AQUR5ePO45/nSCvRFjR2pZphfOe/nygsV2GoAQ77Uvb3lCye5SkJ6DoBEqXtK5xQMRQr0UUCgFrNz6bIw/uIpw7dFG6j4+YgIGBZQvinP9OBX8pInmAxRPrWX/xc1i04gkUB4bw/ADHaUlaPdaEUUzgup1KlzJlrZFvkdKhBl3Sus4JjfRaPaRQCFg8sd4ORlTd8KgJKI2tukbDhxWMua7Lxue+gvUbLyPf13sVBxDWIqI4RjuGIOfhqJSkSKLR7cCTtE4L0d16dJeYMLTbc30Dg7Y9HU08CgI2ecWx/R+Qxiru3EtfwEXPuRY/sKs4EYjjmDg2zd1hGxTaaMJ6hNYG5SiMaALfw3XdFPhuwNtFPlGLFFGnAC8ihJEGIMjlG3WZhY+MgGXLCn31/V8CrgzyJa687t2MLV1hydSGWj0iiiJANb26ZICVws7uCHFjFRdrhY6FfA4ct6UPLbBZAiQhp8u8QJtkdFcN63I3VVIoPgICNnl99f1fBq4YHB3nhTe+l1yhCAJz1Tq1WtjcDbZjmf61rTmuQikHEW1NYQxxbM8GCvkA11EkApMe8eS3U+zb5om2tG6T5nxhXgJKCx/8sIgFf/Ub3o8f5Ii1YXa2ita6AdxiVso2aLevpPEMoHAdB6XAiBDHlghjNIiQz/nN0UlLQTdr0HpOAeySliZCNeo2xkoCigrQ3IHpScDkfXchItcFhRJX3fhe/CBHFGumZyqISQFFIaqhzC3UGSlwXYXrOjjKQUxMbHRzD0AakpA5rugm/vOYR7qkJb+B6wJQr1nXWCnnKDA8LwG1uVm23fZJAK587bvIF4rE2nDyZMWyrmyjGRJIn/N0HB3huS6uG6OUQmvTmDAFxLrHhVwyoaaAtxGQmfzaRrzTYti4H1gCytPHbUdcfz+wbl4CfrT189Tnypx36QsZW7oSEeHkybI9U1OgRDVOuqQ16s3jLyCRiDQBntP8RLFDPbSWAXwEBwUEgd8FeA8S2kW+h3ks5i2xh/bbrXTHL/wc+KOeBBQWrFm+50ffx/U8Nm5+KQCz5RpRrBvjqkBZr06UQkn3UbcSkfUMfc8n9DVebIjimDCMmxKlHJvf9ZyWeWzX//nMYxeLoRT09eVBYM/ddwAQFBdn1sUdBDiuvF7HMRdd8WqCXEAcayqNRUULcEu/Sc75mkQkZCT/p3I6isDz0Z4h8lziSBOGMcqxptNBkVM+jlJdgUM3sW+XglbaQH8fSilmZ6aZOrAbhP39Ky/5RVo42wlwgT8DeMIFmwAol2uYhqQrkRYJiSpkZD0LvJsR8j2X2PfwY432DbGuE4YxrrLmUjmKIPCawLMj3wZ6HvMIMDxkPdSd279re6f4rHIDk+5zhoDCwjUXI2bpookNFEslxAiVar3ZaGuWTwFN635XyKnQ+NvzXILAQ2uD1oZ6GBFGMcp1cB0rUZ7rttqdRwo6dB8bHxku4fse1WqVe+/8PMpxMbp+CzCS7lJmaaLEbAJYu/FZAMzVQkzjAkTSSKsz3WbdHp/mpQu75ncche955HyPILBkCNadjiJNFMXNdpMySV3GzNeWzR8EHgsWWN9/++23YrSmuGgDc1O/Otg+Jm1rM7kAYPFKu3Kq1+3NgE5HoyWSzY6l0w2tX9Mtj+C5Dp7vEgR+Y23gIMY6SmGTBOlaNrN7ZLLPjuOwbMkIjoKHHtjL/du/heMXGFh+Ed1CRgUUah20Vk5RFGfsfFrkFZJc+miWzsh5ShukPdaY5X3fw2iD8a3omtigRXC03dezc0IifbZgS//pMI+u47B86Si+71GeneG/P/kOAIbXbEJ5ua4EtK/OlwD4OZs5jOJUA9LsSKfYdYpq8tyx19c2Yp7v4fsuvufieC23NdaGOI57SlD7cy7wmFgxRj7nU6vW2HLLWwnrVYCb8yOru4KHdiug6EfAUUlHWja3Yet6j3jXp86QXqAkUd91MZ4trJXdNhdt0I5CNZyvnu4xipHhEiMjQzgKyrMzbLnlrZSPH0IJW8pTD/w1cNPpEdCjs4n4zQf8dEILu6TitibPdTDigqZ1M8wIWmtcx2lzjMBRMDjQx8hwP75vYRyY3MPWT72DsF5Dob5WLplrmbJXjnqFLAHCLDAiRlCuNUeSnNimbnrRiKoODtoPtrqBzxKQAFMKfNchbhyHK8Bz3ObmitNwooLAp1gMKJXyTUmtzlXZdttn2H33dxpVqg+Wj06+maPzg+8kAB4GRuq1GoW+Ir7nUq9H9B719kPMTqlI7HQnGWnpSsQZHNfDRVMo+EwsX9S75wIz0yfZue0O7r3zi4hogENGmRuqR/Z/rXfBbMgQIMhuhTq3PHuCQl+RwPeo1SIgc4uQ9Jb2fEfYkv3qSEviiRQkGRxHUSoWWmXEqkK9VmP25DEO7dvFnnvu4PjBXyZZ5lB81A/lXSdP7j95uuA7CFA494C86NC++xlbvJR8Icf0zFzbxclOQD0Fv13sU2lp0Gn9ThytYtFaonvu3MKOb3+6a+cVTBqRTyvFxytH9h06PcjZkCHAOOZ7jlHs2fFdzrv4MvoKrU3PDkQp5B2C32V+7ARsvzJS0LTninw+BwK7tn27UYN6COQQwk5QP8Zla/nw5GO+15ghoHp43w/7xlb96uj+ncvL5VlK/f2USgVmZuc6RrpnaNf3TEQyz5KKpKVgaLCEo+Dk1BSVk4cB9lSOTq7jDIR2R8iAfBZg5912BbVguGQ73s35MV0+Xd3j5JlOZygVNyIohAXDAwDcd9e3Eoq668AZIACjvVtc1+cnWz9HvVYj8D2GBkopj6/dE+y+KDHpfKbb6W8bScaWG10wiOc5VMpldv7f1wGqot2zR0D1+N4Day94JkbHbLv9cwCMjg4SBF5PEL3dXzrBGzpAJ+UK+YCx0UFA2HbbZxpzhnygenzvgbNGAMAFm19KrtDPrm3f5OD+SRwFy8ZHcF2nq39vOoD3GPleom8Ez3NZvmzUTu07f8beHXcAHMlp7z3d+nhGCcgV+nnK818FwHc+8Q4q5TKB77Fi6ah1S+cD3QGw25xAppzvuqyeWEzge8xMT3Pnre8GEKXUDceP75056wQArDrvqShRHw1rFbbc8rfUajXy+YBVKxeRy/ltcwLzj7yQXdun4oV8wJrVS8gFHuWZWbZ86C3oKALkPeUjk1/p1b8zTgCAvW4qt88ee5ivffBNVhICj9UrFzM6Ymfqdstgukx43TY2QLFobIhz1owTBHbkv3rzG5mbmQL4ZuXovrefafBwyisyO6KKH74EuG3m2MN86b3Xc+CBvTiOYvHCIdauGWd4qNQ8FjNGOqShBd6mKxRjIwNseMIyFi8aBoRf7vwZX37f9VRnjgPqC5Wjxavh1AuZxyOc+nT44MG5CpuuKo7uuzmsVa6/7SN/w7qLn8cll7+cQiHPsvERxhcPMzM7R7lcY64WEoaxvQ6nFIHn4vkufYUc/aWCXcU1zusq5TJ3/dd/MvnjO5PWbq4cnXwjYM4Y4rZwmvcDvh/PTXFDaWzifwT14d3bvzW6956tnHfZy9hw4bMYGBxkaLDE0OCpX1oQhJPHT3DfD77Bzru+kbjHB0TU6+amJm97TGgeRXhEN0TKR/d9sX/p0jt0GPyT0fFf3Lv11ty9W29ldNk61px/GYsn1lMaHCZfKNqzfxHCMCKs1ShPn+BXe37C5I/uZGaqadbngP8IYvUPJ05MTj/u6E4jzEvADR/ZJplZPfXO0NzMcfbs+C4P/uIupg7sticvpxlyfYOMr38aS9ZdWHSD4k1i5KbWez6mi8XonpZ9/6gzzU66prWp80gJmC8U+oc59xlXs+HpV3Hi0D6O7N/JiUP7KJ84TLU8jY6qKOUSFPrJFfoJSoMsWLKGocXnUBhalHlp6tcZuhLwoddeeEbeFXrgTFT6GMPZemHiNzY0JUBQa9/wiR0//R14dzhHak5Iq0AOOBdo2wKT5k9zA6PjAohki/2GvzucDl48W9jt9VefjArtRabf9neHI3sPAcepAfw/AhxkH2AEn54AAAAASUVORK5CYII=
+# new iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAPdEVYdEF1dGhvcgBbd21heWVyXauF7RsAAAAYdEVYdENyZWF0aW9uIFRpbWUAMjAxMS0xMC0xMEUb11UAABFMSURBVHic5Zt5kFxHfcc//a45dvbS7upYXSvJEkLYJLHlg8NBGCLANsRgMMQJBEjA2MQuCJAQKoQQSIWCkAKDw1EBAmXu4hDBBiJjSKi4JGwBNodkSawlI8s6VsfuzuzMvPe6f/mj5828N8dKPiQo6KqZ6dfT1/fbv1//fn08+B0P6i2f+vFarfgqxmAEjBHECCIGIwYREC0YBIxBC4g2CIIRQYzNY4yxzyKI0QiNciKN8hoRwAhabBtGNDTaNEgrv7H1ixG0ERCxfTG2fttHY+Mitk4jCKk8zTYMJqmj8Z82BoXave/2t17txbh5JfpcQQHSoCWJNiKNH/uvkM5KkpYuhgKRVhYFiP03UwzVSpG2lExXpK29TGOZrjafpWvWbJ2Al0rfoxy52sSNLErjKCCEsFFMOQYdJbUolFKoOCZKiiiFGypCYpvFARUpwkZ9KFCxwqAa+TUqtIU1CpwQFYFu1I9SqDhCATp5DsEltH1yFCpSKEJi1UAWKxwUkYpsG6FCoQDQTgixWgt8JQHdJEAh9X971caf8lseVl/+nsyz1y3TjR+/WySj0y3dTHSrpWempZc90hJdzNbVnmaoHD/M9KE9TB/ZR1SdIazOEtfnEDE4XoCf7yfoW0B+cDHFkeUU+pdgoFVnY57I9rE1L+zZ8hbVjrUrAWczRLUKB3fdxaHd2wmrsz3z6bCKDqvUZo4w8/AuAPx8PwPjGxhc9gc4udKjan9eAv79+ks6GHu8wtDQxFDoq39W8GogDzCydDUbLtrM0nVPptA3iOf7KMdFKYWIIY4i5manObx/Fzu3b+XQAz/n2OR2jk1ur4vIJ91c9PbZhx461t7Wuqv+tX0KbYZfiwQUR1e9IFJ8RMG4chw2PvulPOlpl5Mr9PUso5SDH+QYHFnI4MhC1p3/h9Sqc9y/43v88PZP50wcX2/C4JrS6MRflaf2feF0+3K2CXCLY6s+qOD1AE962hVccsXL8bygmUESfwQBQ9MXAUFhLY/jKjzHJV8o8ntPv4INF2/mnm9/jvt+sGVElPp8aXT1M8pTwzfBjqhHP5rh7BFwzjm54rS+VcGLc/k+Ln/NP7Jw+RqAptNjTEpSxaarxGo3SBFjkFioSYTnOQS+j+/7POX5f87aC57JNz/299Sr5df1jR1bUfHHX8LBg3Pzdcs5k5hTwe2b1l9X8OLS8BjXvu3jTfDGCEZbgKrhW1gfAU41AUWRplypUquFiMDo+Ar+5O8+xuDYUkBd3hflvgSb5h3ks0JA3+iqfwGeOzg6zjVvupkgXwAEra0ZVKoNfC/okv5IM16rR8xWqhgj5PIFXvyG9zM4Og5wRXF0383z9e2ME1AaW3UNijf7QY4X3fQ+/CCHCOjYAC3g9pMddYtPUrgly0HKtdaxZma2gtYGzw+46sb3kSv0oZS6vjq1p2f/zigBQ0MTQwK3AOrK172bIF9oLEZ0w5W2ok5Kz+3HxruNdisTTac/iWojTM9W0MaQLxS4/DXvAuDkL/8XE9fOPgGRp94GjG546vNYuMzqvNY6s2hpAU5/ktFtH/0u0tBGitHCzPQciLBw2QTnXvrHmLjGzIM/PLsE5JesWoniJqUUlzzv5Q3wiUlrrfAyoNPgM2nt0jH/f1GsKc/VAbhw88twPI/q4Z0URpYtPWsEOJG8Eshd8Jxr8XN5q/fapEYtO/JGukjBaYDtJR3lSg2tDUEux/mb/xQRjeN4rz9rBCilrgXYcNFmAGKtW6OOdII3kll8dQOfYS8JXeaHpMxspQrAEzdelsB9hegwg/nxcIRUcWzl7yvlPAvkfEQ9EVgIjA+MLqFQ6re6GRu7T9LsvJ3v0xsiFkM7SelJsTHSp5COJFKdCxnoL1Is9bNwxXqOPLhr6ez+bRtKqy997AQUR5ePO45/nSCvRFjR2pZphfOe/nygsV2GoAQ77Uvb3lCye5SkJ6DoBEqXtK5xQMRQr0UUCgFrNz6bIw/uIpw7dFG6j4+YgIGBZQvinP9OBX8pInmAxRPrWX/xc1i04gkUB4bw/ADHaUlaPdaEUUzgup1KlzJlrZFvkdKhBl3Sus4JjfRaPaRQCFg8sd4ORlTd8KgJKI2tukbDhxWMua7Lxue+gvUbLyPf13sVBxDWIqI4RjuGIOfhqJSkSKLR7cCTtE4L0d16dJeYMLTbc30Dg7Y9HU08CgI2ecWx/R+Qxiru3EtfwEXPuRY/sKs4EYjjmDg2zd1hGxTaaMJ6hNYG5SiMaALfw3XdFPhuwNtFPlGLFFGnAC8ihJEGIMjlG3WZhY+MgGXLCn31/V8CrgzyJa687t2MLV1hydSGWj0iiiJANb26ZICVws7uCHFjFRdrhY6FfA4ct6UPLbBZAiQhp8u8QJtkdFcN63I3VVIoPgICNnl99f1fBq4YHB3nhTe+l1yhCAJz1Tq1WtjcDbZjmf61rTmuQikHEW1NYQxxbM8GCvkA11EkApMe8eS3U+zb5om2tG6T5nxhXgJKCx/8sIgFf/Ub3o8f5Ii1YXa2ita6AdxiVso2aLevpPEMoHAdB6XAiBDHlghjNIiQz/nN0UlLQTdr0HpOAeySliZCNeo2xkoCigrQ3IHpScDkfXchItcFhRJX3fhe/CBHFGumZyqISQFFIaqhzC3UGSlwXYXrOjjKQUxMbHRzD0AakpA5rugm/vOYR7qkJb+B6wJQr1nXWCnnKDA8LwG1uVm23fZJAK587bvIF4rE2nDyZMWyrmyjGRJIn/N0HB3huS6uG6OUQmvTmDAFxLrHhVwyoaaAtxGQmfzaRrzTYti4H1gCytPHbUdcfz+wbl4CfrT189Tnypx36QsZW7oSEeHkybI9U1OgRDVOuqQ16s3jLyCRiDQBntP8RLFDPbSWAXwEBwUEgd8FeA8S2kW+h3ks5i2xh/bbrXTHL/wc+KOeBBQWrFm+50ffx/U8Nm5+KQCz5RpRrBvjqkBZr06UQkn3UbcSkfUMfc8n9DVebIjimDCMmxKlHJvf9ZyWeWzX//nMYxeLoRT09eVBYM/ddwAQFBdn1sUdBDiuvF7HMRdd8WqCXEAcayqNRUULcEu/Sc75mkQkZCT/p3I6isDz0Z4h8lziSBOGMcqxptNBkVM+jlJdgUM3sW+XglbaQH8fSilmZ6aZOrAbhP39Ky/5RVo42wlwgT8DeMIFmwAol2uYhqQrkRYJiSpkZD0LvJsR8j2X2PfwY432DbGuE4YxrrLmUjmKIPCawLMj3wZ6HvMIMDxkPdSd279re6f4rHIDk+5zhoDCwjUXI2bpookNFEslxAiVar3ZaGuWTwFN635XyKnQ+NvzXILAQ2uD1oZ6GBFGMcp1cB0rUZ7rttqdRwo6dB8bHxku4fse1WqVe+/8PMpxMbp+CzCS7lJmaaLEbAJYu/FZAMzVQkzjAkTSSKsz3WbdHp/mpQu75ncche955HyPILBkCNadjiJNFMXNdpMySV3GzNeWzR8EHgsWWN9/++23YrSmuGgDc1O/Otg+Jm1rM7kAYPFKu3Kq1+3NgE5HoyWSzY6l0w2tX9Mtj+C5Dp7vEgR+Y23gIMY6SmGTBOlaNrN7ZLLPjuOwbMkIjoKHHtjL/du/heMXGFh+Ed1CRgUUah20Vk5RFGfsfFrkFZJc+miWzsh5ShukPdaY5X3fw2iD8a3omtigRXC03dezc0IifbZgS//pMI+u47B86Si+71GeneG/P/kOAIbXbEJ5ua4EtK/OlwD4OZs5jOJUA9LsSKfYdYpq8tyx19c2Yp7v4fsuvufieC23NdaGOI57SlD7cy7wmFgxRj7nU6vW2HLLWwnrVYCb8yOru4KHdiug6EfAUUlHWja3Yet6j3jXp86QXqAkUd91MZ4trJXdNhdt0I5CNZyvnu4xipHhEiMjQzgKyrMzbLnlrZSPH0IJW8pTD/w1cNPpEdCjs4n4zQf8dEILu6TitibPdTDigqZ1M8wIWmtcx2lzjMBRMDjQx8hwP75vYRyY3MPWT72DsF5Dob5WLplrmbJXjnqFLAHCLDAiRlCuNUeSnNimbnrRiKoODtoPtrqBzxKQAFMKfNchbhyHK8Bz3ObmitNwooLAp1gMKJXyTUmtzlXZdttn2H33dxpVqg+Wj06+maPzg+8kAB4GRuq1GoW+Ir7nUq9H9B719kPMTqlI7HQnGWnpSsQZHNfDRVMo+EwsX9S75wIz0yfZue0O7r3zi4hogENGmRuqR/Z/rXfBbMgQIMhuhTq3PHuCQl+RwPeo1SIgc4uQ9Jb2fEfYkv3qSEviiRQkGRxHUSoWWmXEqkK9VmP25DEO7dvFnnvu4PjBXyZZ5lB81A/lXSdP7j95uuA7CFA494C86NC++xlbvJR8Icf0zFzbxclOQD0Fv13sU2lp0Gn9ThytYtFaonvu3MKOb3+6a+cVTBqRTyvFxytH9h06PcjZkCHAOOZ7jlHs2fFdzrv4MvoKrU3PDkQp5B2C32V+7ARsvzJS0LTninw+BwK7tn27UYN6COQQwk5QP8Zla/nw5GO+15ghoHp43w/7xlb96uj+ncvL5VlK/f2USgVmZuc6RrpnaNf3TEQyz5KKpKVgaLCEo+Dk1BSVk4cB9lSOTq7jDIR2R8iAfBZg5912BbVguGQ73s35MV0+Xd3j5JlOZygVNyIohAXDAwDcd9e3Eoq668AZIACjvVtc1+cnWz9HvVYj8D2GBkopj6/dE+y+KDHpfKbb6W8bScaWG10wiOc5VMpldv7f1wGqot2zR0D1+N4Day94JkbHbLv9cwCMjg4SBF5PEL3dXzrBGzpAJ+UK+YCx0UFA2HbbZxpzhnygenzvgbNGAMAFm19KrtDPrm3f5OD+SRwFy8ZHcF2nq39vOoD3GPleom8Ez3NZvmzUTu07f8beHXcAHMlp7z3d+nhGCcgV+nnK818FwHc+8Q4q5TKB77Fi6ah1S+cD3QGw25xAppzvuqyeWEzge8xMT3Pnre8GEKXUDceP75056wQArDrvqShRHw1rFbbc8rfUajXy+YBVKxeRy/ltcwLzj7yQXdun4oV8wJrVS8gFHuWZWbZ86C3oKALkPeUjk1/p1b8zTgCAvW4qt88ee5ivffBNVhICj9UrFzM6Ymfqdstgukx43TY2QLFobIhz1owTBHbkv3rzG5mbmQL4ZuXovrefafBwyisyO6KKH74EuG3m2MN86b3Xc+CBvTiOYvHCIdauGWd4qNQ8FjNGOqShBd6mKxRjIwNseMIyFi8aBoRf7vwZX37f9VRnjgPqC5Wjxavh1AuZxyOc+nT44MG5CpuuKo7uuzmsVa6/7SN/w7qLn8cll7+cQiHPsvERxhcPMzM7R7lcY64WEoaxvQ6nFIHn4vkufYUc/aWCXcU1zusq5TJ3/dd/MvnjO5PWbq4cnXwjYM4Y4rZwmvcDvh/PTXFDaWzifwT14d3bvzW6956tnHfZy9hw4bMYGBxkaLDE0OCpX1oQhJPHT3DfD77Bzru+kbjHB0TU6+amJm97TGgeRXhEN0TKR/d9sX/p0jt0GPyT0fFf3Lv11ty9W29ldNk61px/GYsn1lMaHCZfKNqzfxHCMCKs1ShPn+BXe37C5I/uZGaqadbngP8IYvUPJ05MTj/u6E4jzEvADR/ZJplZPfXO0NzMcfbs+C4P/uIupg7sticvpxlyfYOMr38aS9ZdWHSD4k1i5KbWez6mi8XonpZ9/6gzzU66prWp80gJmC8U+oc59xlXs+HpV3Hi0D6O7N/JiUP7KJ84TLU8jY6qKOUSFPrJFfoJSoMsWLKGocXnUBhalHlp6tcZuhLwoddeeEbeFXrgTFT6GMPZemHiNzY0JUBQa9/wiR0//R14dzhHak5Iq0AOOBdo2wKT5k9zA6PjAohki/2GvzucDl48W9jt9VefjArtRabf9neHI3sPAcepAfw/AhxkH2AEn54AAAAASUVORK5CYII=
-compound_b64=\
-"""
+compound_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI5ODAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImNvbXBvdW5kLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMSIKICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS91c2VyL0Rvd25sb2Fkcy9jYWQvbXlzdHVmZi9pY29ucy9PcGVuU0NBRF93b3JrYmVuY2gvT3BlblNDQURfRXhwbG9kZV9Hcm91cF85XzMycHgucG5nIgogICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNDUiCiAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0NSI+CiAgPGRlZnMKICAgICBpZD0iZGVmczI5ODIiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTk0Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2E0MDAwMDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM5OTYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlZjI5Mjk7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzOTk4IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzE0MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMTQ1IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzQ2NWE0O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzE0NyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQyODciPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDQyODkiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2Y4N2M3MTtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wNDI5MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmYwMDAwO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4NjQiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4NjYiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcxYjJmODtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2OCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAyNzk1O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4NjQiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzODUwIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNjAyODQ1OSwxLjA0NzE2MzksLTEuOTc5NDAyMSwxLjEzOTUyOTUsMTI3Ljk1ODgsLTc0LjQ1NjkwNykiCiAgICAgICBjeD0iNTEuMzI4ODkyIgogICAgICAgY3k9IjMxLjA3NDE0NiIKICAgICAgIGZ4PSI1MS4zMjg4OTIiCiAgICAgICBmeT0iMzEuMDc0MTQ2IgogICAgICAgcj0iMTkuNTcxNDI4IiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjY0IDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjMyIDogMjEuMzMzMzMzIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI5ODgiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzNzctNiIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM2OTkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN4PSI3Ni4zODMzMzEiCiAgICAgICBjeT0iOTQuMzY5NTY4IgogICAgICAgZng9Ijc2LjM4MzMzMSIKICAgICAgIGZ5PSI5NC4zNjk1NjgiCiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTgxODk0MywwLjE4OTQyOTUsLTAuNDEwOTQyNywyLjEzMDA5MjQsNDAuMTYzNDUzLC0xMjEuMTE1NTkpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzc3Ij4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMzc5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmYWZmMmI7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMzODEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmYWEwMDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzc3IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzcwMSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3g9Ijg0Ljg4MzMyNCIKICAgICAgIGN5PSI3Ny4wNDI4NDciCiAgICAgICBmeD0iODQuODgzMzI0IgogICAgICAgZnk9Ijc3LjA0Mjg0NyIKICAgICAgIHI9IjE5LjQ2NzQzNiIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi44NDkyNDIxLDEuMjU4NTExOSwtMC40MDQwNDE1LDAuOTE0NzQwNywtMTI1Ljg0MTMxLC0xMDAuMjU4MDUpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDA3Ij4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMDA5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmYWZmMmI7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMwMTEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmYWEwMDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBmeT0iNzcuMDQyODQ3IgogICAgICAgZng9Ijg0Ljg4MzMyNCIKICAgICAgIGN5PSI3Ny4wNDI4NDciCiAgICAgICBjeD0iODQuODgzMzI0IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjg0OTI0MjEsMS4yNTg1MTE5LC0wLjQwNDA0MTUsMC45MTQ3NDA3LC0xMjUuODQxMzEsLTEwMC4yNTgwNSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMwMTciCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzc3LTYiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzNzctNiIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM2OTktMiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3g9Ijc2LjM4MzMzMSIKICAgICAgIGN5PSI5NC4zNjk1NjgiCiAgICAgICBmeD0iNzYuMzgzMzMxIgogICAgICAgZnk9Ijk0LjM2OTU2OCIKICAgICAgIHI9IjE5LjQ2NzQzNiIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45ODE4OTQzLDAuMTg5NDI5NSwtMC40MTA5NDI3LDIuMTMwMDkyNCw0MC4xNjM0NTMsLTEyMS4xMTU1OSkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMzNzctNiI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzM3OS0yIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMGFmZmY7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMzODEtNCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAzNGZmO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIHI9IjE5LjQ2NzQzNiIKICAgICAgIGZ5PSI3Ny4wNDI4NDciCiAgICAgICBmeD0iODQuODgzMzI0IgogICAgICAgY3k9Ijc3LjA0Mjg0NyIKICAgICAgIGN4PSI4NC44ODMzMjQiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuODQ5MjQyMSwxLjI1ODUxMTksLTAuNDA0MDQxNSwwLjkxNDc0MDcsLTEyNS44NDEzMSwtMTAwLjI1ODA1KSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzAxNy04IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzM3Ny02IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM1Ij4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODM3IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmYWZmMmI7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4MzkiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmYWEwMDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBmeT0iNzcuMDQyODQ3IgogICAgICAgZng9Ijg0Ljg4MzMyNCIKICAgICAgIGN5PSI3Ny4wNDI4NDciCiAgICAgICBjeD0iODQuODgzMzI0IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjg0OTI0MjEsMS4yNTg1MTE5LC0wLjQwNDA0MTUsMC45MTQ3NDA3LC0xMjUuODQxMzEsLTEwMC4yNTgwNSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM4NDQiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzc3LTYiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzNzctNiIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM2OTktNyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3g9Ijc2LjM4MzMzMSIKICAgICAgIGN5PSI5NC4zNjk1NjgiCiAgICAgICBmeD0iNzYuMzgzMzMxIgogICAgICAgZnk9Ijk0LjM2OTU2OCIKICAgICAgIHI9IjE5LjQ2NzQzNiIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45ODE4OTQzLDAuMTg5NDI5NSwtMC40MTA5NDI3LDIuMTMwMDkyNCw0MC4xNjM0NTMsLTEyMS4xMTU1OSkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMzNzctMiI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzM3OS03IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmYWZmMmI7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDMzODEtOCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZhYTAwO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIHI9IjE5LjQ2NzQzNiIKICAgICAgIGZ5PSI3Ny4wNDI4NDciCiAgICAgICBmeD0iODQuODgzMzI0IgogICAgICAgY3k9Ijc3LjA0Mjg0NyIKICAgICAgIGN4PSI4NC44ODMzMjQiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuODQ5MjQyMSwxLjI1ODUxMTksLTAuNDA0MDQxNSwwLjkxNDc0MDcsLTEyNS44NDEzMSwtMTAwLjI1ODA1KSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzAxNy02IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzM3Ny0yIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM1LTEiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4MzctMCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmFmZjJiO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODM5LTkiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmYWEwMDtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBmeT0iNzcuMDQyODQ3IgogICAgICAgZng9Ijg0Ljg4MzMyNCIKICAgICAgIGN5PSI3Ny4wNDI4NDciCiAgICAgICBjeD0iODQuODgzMzI0IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjg0OTI0MjEsMS4yNTg1MTE5LC0wLjQwNDA0MTUsMC45MTQ3NDA3LC0xMjUuODQxMzEsLTEwMC4yNTgwNSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM4NDQtNyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzNzctNiIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDAzMiI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MWIyZjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNDAzNCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMjc5NTtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A0MDM2IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDAzMiIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDQxMTQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC4xOTAzNjgzMywtMC42MTM4NjM1NywxLjk5ODUzLC0wLjE5MDkyODAxLC00Ny4xMzMxOTksMTY1LjQ1NTU5KSIKICAgICAgIGN4PSIxMTMuNTAxODciCiAgICAgICBjeT0iNjUuODQ5MjgxIgogICAgICAgZng9IjExMy41MDE4NyIKICAgICAgIGZ5PSI2NS44NDkyODEiCiAgICAgICByPSIxOS40Njc0MzYiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNzEiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDMxNzMiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzE3NSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQwMzItNyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MWIyZjg7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNDAzNC0zIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAyNzk1O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDQwMzYtNiIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQwMzItNyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDQxMTQtMyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjE5MDM2ODMzLC0wLjYxMzg2MzU3LDEuOTk4NTMsLTAuMTkwOTI4MDEsLTQ3LjEzMzE5OSwxNjUuNDU1NTkpIgogICAgICAgY3g9IjExMy41MDE4NyIKICAgICAgIGN5PSI2NS44NDkyODEiCiAgICAgICBmeD0iMTEzLjUwMTg3IgogICAgICAgZnk9IjY1Ljg0OTI4MSIKICAgICAgIHI9IjE5LjQ2NzQzNiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzE3MS05Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcxYjJmODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMTczLTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzE3NS01IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NDAzMi04Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcxYjJmODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A0MDM0LTQiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDAzNi0zIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDAzMi04IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50NDExNC05IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuMTkwMzY4MzMsLTAuNjEzODYzNTcsMS45OTg1MywtMC4xOTA5MjgwMSwtNDcuMTMzMTk5LDE2NS40NTU1OSkiCiAgICAgICBjeD0iMTEzLjUwMTg3IgogICAgICAgY3k9IjY1Ljg0OTI4MSIKICAgICAgIGZ4PSIxMTMuNTAxODciCiAgICAgICBmeT0iNjUuODQ5MjgxIgogICAgICAgcj0iMTkuNDY3NDM2IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTcxLTEiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDMxNzMtMCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMjc5NTtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMTc1LTMiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDMyLTAiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQwMzQtMzciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDAzNi0xIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDAzMi0wIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzcwMyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3g9IjEzMi43MDQ1NCIKICAgICAgIGN5PSI5MC4xOTMyNDUiCiAgICAgICBmeD0iMTMyLjcwNDU0IgogICAgICAgZnk9IjkwLjE5MzI0NSIKICAgICAgIHI9IjE5LjQ2NzQzNiIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuMDgxNjIzMzksMS4zOTQ5MDcyLC0xLjE1NzI1NjksLTAuMjY5NjMzNzQsMjQ1LjIyNzczLC0xMDUuNDQzNjMpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMjg0Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcxYjJmODtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMjg2IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAyNzk1O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDMyODgiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzNTkzIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzU5OSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3g9IjUxLjYzNzg5NCIKICAgICAgIGN5PSIyNC45NjI3MDQiCiAgICAgICBmeD0iNTEuNjM3ODk0IgogICAgICAgZnk9IjI0Ljk2MjcwNCIKICAgICAgIHI9IjE5LjU3MTQyOCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzU5MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNjOGUwZjk7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzU5NSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzYzN2RjYTtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNTk3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg2NC05IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzU1MiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3g9IjQ4LjY0NTgzNiIKICAgICAgIGN5PSIyNS4xNDkwNDIiCiAgICAgICBmeD0iNDguNjQ1ODM2IgogICAgICAgZnk9IjI1LjE0OTA0MiIKICAgICAgIHI9IjE5LjU3MTQyOCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2NC05Ij4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODY2LTMiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcxYjJmODtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2OC0zIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgcj0iMTkuNTcxNDI4IgogICAgICAgZnk9IjI1LjE0OTA0MiIKICAgICAgIGZ4PSI0OC42NDU4MzYiCiAgICAgICBjeT0iMjUuMTQ5MDQyIgogICAgICAgY3g9IjQ4LjY0NTgzNiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzMwNCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4NjQtOSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDI4NyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDQyODUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuNTQzNTU5NTUsLTAuNjk5NTk1NjcsMS4wOTI0MjQ5LC0wLjYxNDEwNTU4LDk1LjY2NzY0MiwyMDMuMTYxNjEpIgogICAgICAgY3g9IjExMi43NzE4IgogICAgICAgY3k9IjY2LjI1NTUzMSIKICAgICAgIGZ4PSIxMTIuNzcxOCIKICAgICAgIGZ5PSI2Ni4yNTU1MzEiCiAgICAgICByPSIxOS40Njc0MzYiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDQyODciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MjkzIgogICAgICAgeDE9IjI1LjU1OTc3MSIKICAgICAgIHkxPSI0OC40MDM3NTkiCiAgICAgICB4Mj0iMzEuNDc3NTM1IgogICAgICAgeTI9IjUyLjcxMDY4NiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICByPSIxOS41NzE0MjgiCiAgICAgICBmeT0iMjUuMTQ5MDQyIgogICAgICAgZng9IjQ4LjY0NTgzNiIKICAgICAgIGN5PSIyNS4xNDkwNDIiCiAgICAgICBjeD0iNDguNjQ1ODM2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMzA0LTMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODY0LTktNiIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2NC05LTYiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4NjYtMy03IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MWIyZjg7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4NjgtMy01IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgcj0iMTkuNTcxNDI4IgogICAgICAgZnk9IjI1LjE0OTA0MiIKICAgICAgIGZ4PSI0OC42NDU4MzYiCiAgICAgICBjeT0iMjUuMTQ5MDQyIgogICAgICAgY3g9IjQ4LjY0NTgzNiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzA5MCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMxNDMiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuNjMyOTQwMjksMC45MzA4OTEzMiwtMC44MjY5NTM3NiwwLjU2MjI3MDAyLDM4LjY1MzAyMiwtMzQuMjc1NDk2KSIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgcj0iMTkuNTcxNDI4IgogICAgICAgZnk9IjI1LjE0OTA0MiIKICAgICAgIGZ4PSI0OC42NDU4MzYiCiAgICAgICBjeT0iMjUuMTQ5MDQyIgogICAgICAgY3g9IjQ4LjY0NTgzNiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzA5MC01IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg2NC05LTYtNiIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2NC05LTYtNiI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2Ni0zLTctMiIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODY4LTMtNS05IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgcj0iMTkuNTcxNDI4IgogICAgICAgZnk9IjI1LjE0OTA0MiIKICAgICAgIGZ4PSI0OC42NDU4MzYiCiAgICAgICBjeT0iMjUuMTQ5MDQyIgogICAgICAgY3g9IjQ4LjY0NTgzNiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzA5MC0yIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzE0My03IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjYzMjk0MDI5LDAuOTMwODkxMzIsLTAuODI2OTUzNzYsMC41NjIyNzAwMiwzOC42NTMwMjIsLTM0LjI3NTQ5NikiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNDMtNyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMTQ1LTAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMTQ3LTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICByPSIxOS41NzE0MjgiCiAgICAgICBmeT0iMjUuMTQ5MDQyIgogICAgICAgZng9IjQ4LjY0NTgzNiIKICAgICAgIGN5PSIyNS4xNDkwNDIiCiAgICAgICBjeD0iNDguNjQ1ODM2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjYzMjk0MDI5LDAuOTMwODkxMzIsLTAuODI2OTUzNzYsMC41NjIyNzAwMiwzOC42NTMwMjIsLTM0LjI3NTQ5NikiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMxNjUiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMTQzLTciCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM5OTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDAwIgogICAgICAgeDE9IjYyLjAwMDAwNCIKICAgICAgIHkxPSIzNCIKICAgICAgIHgyPSI1MiIKICAgICAgIHkyPSIzNCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgc3ByZWFkTWV0aG9kPSJyZWZsZWN0IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjg3NjQ4NTU1LDAsMCwxLjEwNjgxMjgsMC44MTc2MDQxNiwxLjMyNzc3MzMpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzOTk0LTMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDAwLTIiCiAgICAgICB4MT0iNjIuMDAwMDA0IgogICAgICAgeTE9IjM0IgogICAgICAgeDI9IjUyIgogICAgICAgeTI9IjM0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBzcHJlYWRNZXRob2Q9InJlZmxlY3QiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuODc2NDg1NTUsMCwwLDEuMTA2ODEyOCwwLjgxNzYwNDE2LDEuMzI3NzczMykiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5OTQtMyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzOTk2LTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlZjI5Mjk7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzOTk4LTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6em9vbT0iMy40MjUwNDg1IgogICAgIGlua3NjYXBlOmN4PSI0Ny4xMzE2ODkiCiAgICAgaW5rc2NhcGU6Y3k9IjEyLjgzNDU4OCIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJnMzU2MCIKICAgICBzaG93Z3JpZD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTUzNiIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI4MDEiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIgogICAgIGlua3NjYXBlOnNuYXAtZ2xvYmFsPSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTpzbmFwLW5vZGVzPSJ0cnVlIgogICAgIHNob3dndWlkZXM9InRydWUiCiAgICAgaW5rc2NhcGU6Z3VpZGUtYmJveD0idHJ1ZSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDczIgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTI5ODUiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bS2VpdGggU2xvYW5dPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjcmVhdG9yPgogICAgICAgIDxkYzp0aXRsZT5PcGVuU0NBRF9IdWxsPC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDEzLTEwLTMwPC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL09wZW5TQ0FEL1Jlc291cmNlcy9pY29ucy9PcGVuU0NBRF9IdWxsLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8Y2M6bGljZW5zZT5odHRwczovL3d3dy5nbnUub3JnL2NvcHlsZWZ0L2xlc3Nlci5odG1sPC9jYzpsaWNlbnNlPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPGcKICAgICAgIGlkPSJnMzU2MCIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuOTEyNzM2MTgsMCwwLDAuOTAzNDk1MTUsMTA3Ljg1Mzc0LC0xLjE5OTYzNjcpIj4KICAgICAgPGcKICAgICAgICAgaWQ9Imc0NjEyIgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjcxOTAxNDg3LDAsMCwwLjcxOTAxNDg3LC0yMy4zNTE1MTUsMTAuMzI1MDE5KSI+CiAgICAgICAgPGcKICAgICAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNC4xOTU0NzI5ZS02LDIuMzQyNTIwOWUtNikiCiAgICAgICAgICAgaWQ9Imc5MjkiPgogICAgICAgICAgPHBhdGgKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiMzNDY1YTQ7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgICAgIGQ9Ik0gOSwyOCAyOSw4IDU4LDMyIDM1LDU2IFoiCiAgICAgICAgICAgICBpZD0icGF0aDQxODciCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4wOTU2MDY4LDAsMCwxLjEwNjgxMjgsLTExOC4xNjUzLDEuMzI3NzczMykiIC8+CiAgICAgICAgICA8cGF0aAogICAgICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgICAgZD0ibSAzNCw1NCAxOS4wMDAwMDYsLTIwIC0yMywtMjQgTCA5LDMxIDMyLjAwMDAwNiw1MSBaIgogICAgICAgICAgICAgaWQ9InBhdGgzMDg5IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMDk1NjA2OCwwLDAsMS4xMDY4MTI4LC0xMTguMTY1MywxLjMyNzc3MzMpIgogICAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2MiIC8+CiAgICAgICAgICA8Y2lyY2xlCiAgICAgICAgICAgICByPSIxOC41NzE0MjgiCiAgICAgICAgICAgICBjeT0iMzQuNTcxNDI2IgogICAgICAgICAgICAgY3g9IjUzLjIxNDI4NyIKICAgICAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMTIwOTU0MSwwLDAsMS4xMzI0MTk0LC0xMzEuODAwNTcsLTEzLjQ3MTY5OSkiCiAgICAgICAgICAgICBpZD0icGF0aDM1NTAtMyIKICAgICAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtmaWxsOnVybCgjcmFkaWFsR3JhZGllbnQzMDkwKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MS45NTI2NTMyOTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyOm5vbmU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIgLz4KICAgICAgICAgIDxjaXJjbGUKICAgICAgICAgICAgIHI9IjE4LjU3MTQyOCIKICAgICAgICAgICAgIGN5PSIzNC41NzE0MjYiCiAgICAgICAgICAgICBjeD0iNTMuMjE0Mjg3IgogICAgICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4wMDI5NjU5LDAsMCwxLjAxMzIyNDEsLTEyNS41MjE5MiwtOS4zNTA5NDk0KSIKICAgICAgICAgICAgIGlkPSJwYXRoMzU1MC0zLTEiCiAgICAgICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTt2aXNpYmlsaXR5OnZpc2libGU7ZmlsbDpub25lO3N0cm9rZTojMzQ2NWE0O3N0cm9rZS13aWR0aDoyLjE4MjM2MjMyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAvPgogICAgICAgICAgPGNpcmNsZQogICAgICAgICAgICAgcj0iMTguNTcxNDI4IgogICAgICAgICAgICAgY3k9IjM0LjU3MTQyNiIKICAgICAgICAgICAgIGN4PSI1My4yMTQyODciCiAgICAgICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjEyMDk1NDEsMCwwLDEuMTMyNDE5NCwtMTUzLjcxMjcyLDguNjY0NTUyNCkiCiAgICAgICAgICAgICBpZD0icGF0aDM1NTAtMy0zIgogICAgICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6dXJsKCNyYWRpYWxHcmFkaWVudDMxNjUpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoxLjk1MjY1MzI5O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAvPgogICAgICAgICAgPGNpcmNsZQogICAgICAgICAgICAgcj0iMTguNTcxNDI4IgogICAgICAgICAgICAgY3k9IjM0LjU3MTQyNiIKICAgICAgICAgICAgIGN4PSI1My4yMTQyODciCiAgICAgICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjAwMjk2NTksMCwwLDEuMDEzMjI0MSwtMTQ3LjQzNDA4LDEyLjc4NTMwMSkiCiAgICAgICAgICAgICBpZD0icGF0aDM1NTAtMy0xLTYiCiAgICAgICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTt2aXNpYmlsaXR5OnZpc2libGU7ZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoyLjE4MjM2MjMyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXI6bm9uZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIiAvPgogICAgICAgIDwvZz4KICAgICAgPC9nPgogICAgICA8ZwogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjE5NTQ1MTgsMCwwLDAuMTk3NDUwODksLTMwOC42NzcxNiwtNzguNjkzMDA1KSIKICAgICAgICAgaWQ9Imc4NDciPgogICAgICAgIDxnCiAgICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC45MjAwMDAwNCwwLDAsMC45OTg1MjgyNiw5Mi4zMjgwOCwxLjEwNzkzMzUpIgogICAgICAgICAgIGlkPSJnMzUyNy0zIgogICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9yZWN0YW5nbGUucG5nIgogICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI2LjU4OTU2NjciCiAgICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjYuNTg5NTY2NyI+CiAgICAgICAgICA8cGF0aAogICAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjY2NjIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiNkM2Q3Y2Y7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMyZTM0MzY7c3Ryb2tlLXdpZHRoOjE1LjI1NjgzNDAzO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgICAgZD0iTSA5NzEuMzEzNDksNDE1Ljk4NDU3IFYgNzUyLjgxMDg2IEggMTMzNi44OTAyIFYgNDE1Ljk4NDU3IFogbSA0My44NjkyMSw0NC4zNjQ5MiAyNzQuMDIzNiwtMC40MzEwNSB2IDI0OC45NTg1NyBsIC0yNzQuMDIzNiwwLjA2NDYgeiIKICAgICAgICAgICAgIGlkPSJyZWN0MjIzMyIgLz4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjYyIKICAgICAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDcuMzExNTM0MiwwLDAsNy4zMTE1MzQyLDkyMC4xMzI3NSwzNTAuNjc2NDgpIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzA0MCIKICAgICAgICAgICAgIGQ9Ik0gNTUuOTEzMDQ1LDEwLjkzNTE0OSBIIDkuMTczOTE2NCB2IDQzLjA2MzM3OCIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjYyIKICAgICAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDcuMzExNTM0MiwwLDAsNy4zMTE1MzQyLDkyMC4xMzI3NSwzNTAuNjc2NDgpIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzA0MiIKICAgICAgICAgICAgIGQ9Im0gMTMsNTEgMzkuNjg1NTc1LDAuMDMyMTkgLTAuMDY5ODcsLTM2LjEyODc1NSIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjIuMDg2NjgwMTc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgICAgPC9nPgogICAgICA8L2c+CiAgICA8L2c+CiAgICA8ZwogICAgICAgaWQ9ImczNzYwLTgiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjQyMTU2MjEsLTAuMDU1NTMxNjksLTAuMDc5MzU0MzgsMC41NDA4NjUyNSwyOC4wMDA0ODUsLTE1LjgxMzE3KSIgLz4KICA8L2c+Cjwvc3ZnPgo=
"""
-shiftX_b64=\
-"""
+shiftX_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMxMTEiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNCByOTkzOSIKICAgc29kaXBvZGk6ZG9jbmFtZT0ic2hpZnRYLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMSI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMxMTMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODQxIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzA2MTljMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODQzIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzc5Y2ZiO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4NDUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODQxIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NjY1NSIKICAgICAgIHgxPSIxNTUuNDY4NzUiCiAgICAgICB5MT0iMjU0NS4yMTg4IgogICAgICAgeDI9IjcxMy4wNjI1IgogICAgICAgeTI9IjI1NDUuMjE4OCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgyLC0yKSIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMTE5IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAsLTEuNDUwMDAwMSwxLjQ3MDU4ODIsMCwtMTUuMDU4ODIsOTEuNDUpIgogICAgICAgeTI9IjM2LjA3OTk5OCIKICAgICAgIHgyPSIyMS42ODk2NTMiCiAgICAgICB5MT0iMjkuMjc5OTk5IgogICAgICAgeDE9IjU2LjE3MjQwOSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAzNiIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIHkyPSIzOS41MTQxMDMiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgxPSI0Mi43NTgwNzYiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsMTIuNTM2ODE2LDIwLjIwNTg4MykiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMjUiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiwzNS4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI1LTMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUtNiI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg5Ny03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTktNSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIHkyPSIzOS41MTQxMDMiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTE9IjI0LjM3OTMwOSIKICAgICAgIHgxPSI1MC4xMjA3ODEiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDUxLjQ2MzE4LDIwLjIwNTg4MykiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNjYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5MDAiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMjIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSIzMCIKICAgICAgIHkxPSI2IgogICAgICAgeDI9IjM0IgogICAgICAgeTI9IjU3IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1LTYtNCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg5Ny03LTAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS01LTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4MT0iNTAuMTIwNzgxIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSw1MS40NjMxOCw2LjIwNTg4MykiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNjYtNCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDM5Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMDQxIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDMwNDMiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMjUtOCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOCIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NS04Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODk3LTIiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS00IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS04IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzE1MCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNTIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTU0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS04IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0MSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNDMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQ1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS04IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0NCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNDYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQ4IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjkuNjg3NSIKICAgICBpbmtzY2FwZTpjeD0iLTMuNDA2NDUxOCIKICAgICBpbmtzY2FwZTpjeT0iMzIiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjEiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii05IgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOSIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1ub2Rlcz0idHJ1ZSIKICAgICBpbmtzY2FwZTpzbmFwLWdsb2JhbD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIj4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDMwNDYiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiIC8+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDQ4IgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIgogICAgICAgc3BhY2luZ3g9IjE2IgogICAgICAgc3BhY2luZ3k9IjE2IgogICAgICAgb3JpZ2lueD0iMCIKICAgICAgIG9yaWdpbnk9IjAiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPGcKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMDYxMjA4LDAsMCwxLjA2MTIwOCwtMS45NTg2NTYsMTIuMDQxMzQ0KSIKICAgICAgIGlkPSJnMzAxMSI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjYyIKICAgICAgICAgaWQ9InBhdGgzMzQzIgogICAgICAgICBkPSJtIDQ5LDE5IDAsOCAtOCwwIDAsMTAgOCwwIDAsOCAxMiwtMTMgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMwNDQpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoxLjk5OTk5OTg4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjYyIKICAgICAgICAgaWQ9InBhdGgzMzQzLTIiCiAgICAgICAgIGQ9Ik0gNTEuMDQwNzQ4LDI0LjQ4NzAyMSA1MSwyOSBsIC04LDAgMCw2IDgsMCAwLjAxNzA1LDUuMTMwNjgyIDcuMjY0MTkxLC04LjEwNjU3NiB6IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoxLjk5OTk5OTg4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2c+CiAgICA8ZwogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4wNjEyMDgsMCwwLDEuMDYxMjA4LC0xLjk1ODY1NiwxMi4wNDEzNDQpIgogICAgICAgaWQ9ImczMDA3Ij4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIgogICAgICAgICBpZD0icGF0aDMzNDMtMyIKICAgICAgICAgZD0ibSAxNSwxOSAwLDggOCwwIDAsMTAgLTgsMCAwLDggTCAzLDMyIHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMDQ2KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoMzM0My0yLTUiCiAgICAgICAgIGQ9Ik0gMTIuOTU5MjUyLDI0LjQ4NzAyMSAxMywyOSBsIDgsMCAwLDYgLTgsMCAtMC4wMTcwNSw1LjEzMDY4MiAtNy4yNjQxOTEsLTguMTA2NTc2IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDwvZz4KICAgIDxnCiAgICAgICBpZD0iZzMxNjAiCiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxOS45MzUwMzksNy45ODgxODkpIj4KICAgICAgPHBhdGgKICAgICAgICAgaWQ9InBhdGgzMTYyIgogICAgICAgICBkPSJtIDE1LjU5MDU1MSwxMS43NjM3OCA3LjkzNzAwOCwxMS42NTc0OCAtNi4xMjk5MjEsMCAtNS4zNTAzOTQsLTcuNzk1Mjc1IC01LjI3OTUyNzUsNy43OTUyNzUgLTYuMTY1MzU0MywwIDcuOTAxNTc0NywtMTEuNjU3NDggLTcuNjE4MTEwMTQsLTExLjE2MTQxNzc4IDYuMTY1MzU0MjQsMCA0Ljk5NjA2Myw3LjMzNDY0NTc4IDQuOTk2MDYzLC03LjMzNDY0NTc4IDYuMTY1MzU0LDAgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6I2Q0MDAwMDtzdHJva2Utd2lkdGg6MS4xNjkyOTEzOHB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2c+CiAgPC9nPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTU3ODEiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlIC8+CiAgICAgICAgPGNjOmxpY2Vuc2UKICAgICAgICAgICByZGY6cmVzb3VyY2U9IiIgLz4KICAgICAgICA8ZGM6ZGF0ZT5Nb24gT2N0IDEwIDEzOjQ0OjUyIDIwMTEgKzAwMDA8L2RjOmRhdGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9EcmFmdC9SZXNvdXJjZXMvaWNvbnMvRHJhZnRfVHJpbWV4LnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bYWdyeXNvbl0gQWxleGFuZGVyIEdyeXNvbjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICA8cmRmOkJhZz4KICAgICAgICAgICAgPHJkZjpsaT5hcnJvdzwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmFycm93czwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmxpbmU8L3JkZjpsaT4KICAgICAgICAgIDwvcmRmOkJhZz4KICAgICAgICA8L2RjOnN1YmplY3Q+CiAgICAgICAgPGRjOmRlc2NyaXB0aW9uPkEgdmVydGljYWwgbGluZSB3aXRoIGFuIGFycm93IHBvaW50aW5nIGF3YXkgZnJvbSBpdCBvbiBlYWNoIHNpZGU8L2RjOmRlc2NyaXB0aW9uPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KPC9zdmc+Cg==
"""
-shiftY_b64=\
-"""
+shiftY_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMxMTEiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNCByOTkzOSIKICAgc29kaXBvZGk6ZG9jbmFtZT0ic2hpZnRYLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMSI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMxMTMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODQxIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzA2MTljMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODQzIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzc5Y2ZiO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4NDUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODQxIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NjY1NSIKICAgICAgIHgxPSIxNTUuNDY4NzUiCiAgICAgICB5MT0iMjU0NS4yMTg4IgogICAgICAgeDI9IjcxMy4wNjI1IgogICAgICAgeTI9IjI1NDUuMjE4OCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgyLC0yKSIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMTE5IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAsLTEuNDUwMDAwMSwxLjQ3MDU4ODIsMCwtMTUuMDU4ODIsOTEuNDUpIgogICAgICAgeTI9IjM2LjA3OTk5OCIKICAgICAgIHgyPSIyMS42ODk2NTMiCiAgICAgICB5MT0iMjkuMjc5OTk5IgogICAgICAgeDE9IjU2LjE3MjQwOSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAzNiIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIHkyPSIzOS41MTQxMDMiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgxPSI0Mi43NTgwNzYiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsMTIuNTM2ODE2LDIwLjIwNTg4MykiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMjUiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiwzNS4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI1LTMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUtNiI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg5Ny03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTktNSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIHkyPSIzOS41MTQxMDMiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTE9IjI0LjM3OTMwOSIKICAgICAgIHgxPSI1MC4xMjA3ODEiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDUxLjQ2MzE4LDIwLjIwNTg4MykiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNjYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5MDAiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMjIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSIzMCIKICAgICAgIHkxPSI2IgogICAgICAgeDI9IjM0IgogICAgICAgeTI9IjU3IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1LTYtNCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg5Ny03LTAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS01LTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4MT0iNTAuMTIwNzgxIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSw1MS40NjMxOCw2LjIwNTg4MykiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNjYtNCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDM5Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMDQxIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDMwNDMiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMjUtOCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOCIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NS04Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODk3LTIiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS00IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS04IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzE1MCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNTIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTU0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS04IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0MSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNDMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQ1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS04IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0NCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNDYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQ4IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjkuNjg3NSIKICAgICBpbmtzY2FwZTpjeD0iLTE2LjgyNTgwNyIKICAgICBpbmtzY2FwZTpjeT0iMzIiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjEiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii05IgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOSIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1ub2Rlcz0idHJ1ZSIKICAgICBpbmtzY2FwZTpzbmFwLWdsb2JhbD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIj4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDMwNDYiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiIC8+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDQ4IgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIgogICAgICAgc3BhY2luZ3g9IjE2IgogICAgICAgc3BhY2luZ3k9IjE2IgogICAgICAgb3JpZ2lueD0iMCIKICAgICAgIG9yaWdpbnk9IjAiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPHRleHQKICAgICAgIHNvZGlwb2RpOmxpbmVzcGFjaW5nPSIxMjUlIgogICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgIHN0eWxlPSJmb250LXNpemU6MzEuMzUyMDM5MzRweDtmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDtsaW5lLWhlaWdodDoxMjUlO2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O2ZpbGw6IzAwODAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzAwNTUwMDtzdHJva2Utd2lkdGg6MS4xNzAxMTc5NztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO2Rpc3BsYXk6aW5saW5lO2ZvbnQtZmFtaWx5OkRlamFWdSBTYW5zOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246RGVqYVZ1IFNhbnMgQm9sZCIKICAgICAgIHg9IjIwLjY0ODY2MyIKICAgICAgIHk9IjMxLjQyNzg3OSIKICAgICAgIGlkPSJ0ZXh0NDE5OSI+PHRzcGFuCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgIGlkPSJ0c3BhbjQyMDEiCiAgICAgICAgIHg9IjIwLjY0ODY2MyIKICAgICAgICAgeT0iMzEuNDI3ODc5IgogICAgICAgICBzdHlsZT0ic3Ryb2tlOiMwMDU1MDA7c3Ryb2tlLXdpZHRoOjEuMTcwMTE3OTc7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiPlk8L3RzcGFuPjwvdGV4dD4KICAgIDxnCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjA2MTIwOCwwLDAsMS4wNjEyMDgsLTEuOTU4NjU2LDEyLjA0MTM0NCkiCiAgICAgICBpZD0iZzMwMTEiPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoMzM0MyIKICAgICAgICAgZD0ibSA0OSwxOSAwLDggLTgsMCAwLDEwIDgsMCAwLDggMTIsLTEzIHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMDQ0KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoMzM0My0yIgogICAgICAgICBkPSJNIDUxLjA0MDc0OCwyNC40ODcwMjEgNTEsMjkgbCAtOCwwIDAsNiA4LDAgMC4wMTcwNSw1LjEzMDY4MiA3LjI2NDE5MSwtOC4xMDY1NzYgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPC9nPgogICAgPGcKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMDYxMjA4LDAsMCwxLjA2MTIwOCwtMS45NTg2NTYsMTIuMDQxMzQ0KSIKICAgICAgIGlkPSJnMzAwNyI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjYyIKICAgICAgICAgaWQ9InBhdGgzMzQzLTMiCiAgICAgICAgIGQ9Im0gMTUsMTkgMCw4IDgsMCAwLDEwIC04LDAgMCw4IEwgMywzMiB6IgogICAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzA0Nik7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIgogICAgICAgICBpZD0icGF0aDMzNDMtMi01IgogICAgICAgICBkPSJNIDEyLjk1OTI1MiwyNC40ODcwMjEgMTMsMjkgbCA4LDAgMCw2IC04LDAgLTAuMDE3MDUsNS4xMzA2ODIgLTcuMjY0MTkxLC04LjEwNjU3NiB6IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoxLjk5OTk5OTg4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2c+CiAgPC9nPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTU3ODEiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgICAgPGNjOmxpY2Vuc2UKICAgICAgICAgICByZGY6cmVzb3VyY2U9IiIgLz4KICAgICAgICA8ZGM6ZGF0ZT5Nb24gT2N0IDEwIDEzOjQ0OjUyIDIwMTEgKzAwMDA8L2RjOmRhdGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9EcmFmdC9SZXNvdXJjZXMvaWNvbnMvRHJhZnRfVHJpbWV4LnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bYWdyeXNvbl0gQWxleGFuZGVyIEdyeXNvbjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICA8cmRmOkJhZz4KICAgICAgICAgICAgPHJkZjpsaT5hcnJvdzwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmFycm93czwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmxpbmU8L3JkZjpsaT4KICAgICAgICAgIDwvcmRmOkJhZz4KICAgICAgICA8L2RjOnN1YmplY3Q+CiAgICAgICAgPGRjOmRlc2NyaXB0aW9uPkEgdmVydGljYWwgbGluZSB3aXRoIGFuIGFycm93IHBvaW50aW5nIGF3YXkgZnJvbSBpdCBvbiBlYWNoIHNpZGU8L2RjOmRlc2NyaXB0aW9uPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KPC9zdmc+Cg==
"""
-shiftZ_b64=\
-"""
+shiftZ_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMxMTEiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNCByOTkzOSIKICAgc29kaXBvZGk6ZG9jbmFtZT0ic2hpZnRYLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMSI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMxMTMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODQxIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzA2MTljMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODQzIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzc5Y2ZiO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4NDUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODQxIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NjY1NSIKICAgICAgIHgxPSIxNTUuNDY4NzUiCiAgICAgICB5MT0iMjU0NS4yMTg4IgogICAgICAgeDI9IjcxMy4wNjI1IgogICAgICAgeTI9IjI1NDUuMjE4OCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgyLC0yKSIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMTE5IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAsLTEuNDUwMDAwMSwxLjQ3MDU4ODIsMCwtMTUuMDU4ODIsOTEuNDUpIgogICAgICAgeTI9IjM2LjA3OTk5OCIKICAgICAgIHgyPSIyMS42ODk2NTMiCiAgICAgICB5MT0iMjkuMjc5OTk5IgogICAgICAgeDE9IjU2LjE3MjQwOSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAzNiIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIHkyPSIzOS41MTQxMDMiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgxPSI0Mi43NTgwNzYiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsMTIuNTM2ODE2LDIwLjIwNTg4MykiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMjUiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiwzNS4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI1LTMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUtNiI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg5Ny03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTktNSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIHkyPSIzOS41MTQxMDMiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTE9IjI0LjM3OTMwOSIKICAgICAgIHgxPSI1MC4xMjA3ODEiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDUxLjQ2MzE4LDIwLjIwNTg4MykiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNjYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM5MDAiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMjIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSIzMCIKICAgICAgIHkxPSI2IgogICAgICAgeDI9IjM0IgogICAgICAgeTI9IjU3IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1LTYtNCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg5Ny03LTAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS01LTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4MT0iNTAuMTIwNzgxIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSw1MS40NjMxOCw2LjIwNTg4MykiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNjYtNCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDM5Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMDQxIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDMwNDMiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMjUtOCIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOCIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NS04Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODk3LTIiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS00IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS04IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzE1MCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNTIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTU0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS04IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0MSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNDMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQ1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS04IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0NCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNDYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQ4IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjkuNjg3NSIKICAgICBpbmtzY2FwZTpjeD0iLTIxLjEwOTY3OCIKICAgICBpbmtzY2FwZTpjeT0iMzIiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjEiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii05IgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOSIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1ub2Rlcz0idHJ1ZSIKICAgICBpbmtzY2FwZTpzbmFwLWdsb2JhbD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIj4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDMwNDYiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiIC8+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDQ4IgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIgogICAgICAgc3BhY2luZ3g9IjE2IgogICAgICAgc3BhY2luZ3k9IjE2IgogICAgICAgb3JpZ2lueD0iMCIKICAgICAgIG9yaWdpbnk9IjAiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPGcKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMDYxMjA4LDAsMCwxLjA2MTIwOCwtMS45NTg2NTYsMTIuMDQxMzQ0KSIKICAgICAgIGlkPSJnMzAxMSI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjYyIKICAgICAgICAgaWQ9InBhdGgzMzQzIgogICAgICAgICBkPSJtIDQ5LDE5IDAsOCAtOCwwIDAsMTAgOCwwIDAsOCAxMiwtMTMgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMwNDQpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoxLjk5OTk5OTg4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjYyIKICAgICAgICAgaWQ9InBhdGgzMzQzLTIiCiAgICAgICAgIGQ9Ik0gNTEuMDQwNzQ4LDI0LjQ4NzAyMSA1MSwyOSBsIC04LDAgMCw2IDgsMCAwLjAxNzA1LDUuMTMwNjgyIDcuMjY0MTkxLC04LjEwNjU3NiB6IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoxLjk5OTk5OTg4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2c+CiAgICA8ZwogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4wNjEyMDgsMCwwLDEuMDYxMjA4LC0xLjk1ODY1NiwxMi4wNDEzNDQpIgogICAgICAgaWQ9ImczMDA3Ij4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIgogICAgICAgICBpZD0icGF0aDMzNDMtMyIKICAgICAgICAgZD0ibSAxNSwxOSAwLDggOCwwIDAsMTAgLTgsMCAwLDggTCAzLDMyIHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMDQ2KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoMzM0My0yLTUiCiAgICAgICAgIGQ9Ik0gMTIuOTU5MjUyLDI0LjQ4NzAyMSAxMywyOSBsIDgsMCAwLDYgLTgsMCAtMC4wMTcwNSw1LjEzMDY4MiAtNy4yNjQxOTEsLTguMTA2NTc2IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDwvZz4KICAgIDx0ZXh0CiAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgc3R5bGU9ImZvbnQtc2l6ZTozMi4yNzA0OTYzN3B4O2ZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO3RleHQtYWxpZ246c3RhcnQ7bGluZS1oZWlnaHQ6NzYuOTk5OTk4MDklO2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuMjA0Mzk4MTY7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtmb250LWZhbWlseTpTYW5zOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246U2FucyBCb2xkIgogICAgICAgeD0iMjIuMjcwMDA0IgogICAgICAgeT0iMzEuNDQ5OTQ0IgogICAgICAgaWQ9InRleHQ0NDk5LTEiCiAgICAgICBzb2RpcG9kaTpsaW5lc3BhY2luZz0iNzYuOTk5OTk4JSI+PHRzcGFuCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgIGlkPSJ0c3BhbjQ0OTctNyIKICAgICAgICAgeD0iMjIuMjcwMDA0IgogICAgICAgICB5PSIzMS40NDk5NDQiCiAgICAgICAgIHN0eWxlPSJmb250LXNpemU6MzIuMjcwNDk2MzdweDtmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O2xpbmUtaGVpZ2h0Ojc2Ljk5OTk5ODA5JTt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7ZmlsbDojMDAwMGZmO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxLjIwNDM5ODE2O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7Zm9udC1mYW1pbHk6U2FuczstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOlNhbnMgQm9sZCI+WjwvdHNwYW4+PC90ZXh0PgogIDwvZz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGE1NzgxIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZT48L2RjOnRpdGxlPgogICAgICAgIDxjYzpsaWNlbnNlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSIiIC8+CiAgICAgICAgPGRjOmRhdGU+TW9uIE9jdCAxMCAxMzo0NDo1MiAyMDExICswMDAwPC9kYzpkYXRlPgogICAgICAgIDxkYzpjcmVhdG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W3dtYXllcl08L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnJpZ2h0cz4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkZyZWVDQUQgTEdQTDIrPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpyaWdodHM+CiAgICAgICAgPGRjOnB1Ymxpc2hlcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkZyZWVDQUQ8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnB1Ymxpc2hlcj4KICAgICAgICA8ZGM6aWRlbnRpZmllcj5GcmVlQ0FEL3NyYy9Nb2QvRHJhZnQvUmVzb3VyY2VzL2ljb25zL0RyYWZ0X1RyaW1leC5zdmc8L2RjOmlkZW50aWZpZXI+CiAgICAgICAgPGRjOnJlbGF0aW9uPmh0dHA6Ly93d3cuZnJlZWNhZHdlYi5vcmcvd2lraS9pbmRleC5waHA/dGl0bGU9QXJ0d29yazwvZGM6cmVsYXRpb24+CiAgICAgICAgPGRjOmNvbnRyaWJ1dG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2Fncnlzb25dIEFsZXhhbmRlciBHcnlzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICAgIDxkYzpzdWJqZWN0PgogICAgICAgICAgPHJkZjpCYWc+CiAgICAgICAgICAgIDxyZGY6bGk+YXJyb3c8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5hcnJvd3M8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5saW5lPC9yZGY6bGk+CiAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICAgIDxkYzpkZXNjcmlwdGlvbj5BIHZlcnRpY2FsIGxpbmUgd2l0aCBhbiBhcnJvdyBwb2ludGluZyBhd2F5IGZyb20gaXQgb24gZWFjaCBzaWRlPC9kYzpkZXNjcmlwdGlvbj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+Cjwvc3ZnPgo=
"""
-rotateX_b64=\
-"""
+rotateX_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMwMDAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNCByOTkzOSIKICAgc29kaXBvZGk6ZG9jbmFtZT0icm90YXRlWC5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMzMDAyIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzM5MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMzk1IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM5NyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzOTMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzk5IgogICAgICAgeDE9IjE5NDIuNzM4MiIKICAgICAgIHkxPSIxOTM0Ljc1NiIKICAgICAgIHgyPSIxODA5LjUwMjEiCiAgICAgICB5Mj0iMTU0Ny40MTM1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjk4NjU3ODExLDAsMCwwLjk5OTIyMDc4LDM3MDYuODY1OCwtMi42ODExNjk3KSIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMDA4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzkzLTciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzk5LTEiCiAgICAgICB4MT0iMTY2OS43MzE0IgogICAgICAgeTE9IjE3MjYuMDU4NSIKICAgICAgIHgyPSIyMDY3LjE3MDIiCiAgICAgICB5Mj0iMTcyNi4wNTg1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTg2NTc4MTEsMCwwLDAuOTk5MjIwNzgsMjAuMTI5MjUxLC0yLjY4MTE2OTcpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzkzLTciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAzZGRkO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDMzOTUtNCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzYzOWVmMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMzk3LTAiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzkzLTEiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyOTk5IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTg2NTc4MTEsMCwwLDAuOTk5MjIwNzgsMjAuMTI5MjUxLC0yLjY4MTE2OTcpIgogICAgICAgeDE9IjE5NDIuNzM4MiIKICAgICAgIHkxPSIxOTM0Ljc1NiIKICAgICAgIHgyPSIxODA5LjUwMjEiCiAgICAgICB5Mj0iMTU0Ny40MTM1IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzkzLTEiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzM5NS03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM5Ny00IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjYuODUwMDk2OSIKICAgICBpbmtzY2FwZTpjeD0iLTI1LjIzNDM2OCIKICAgICBpbmtzY2FwZTpjeT0iMjkuNDY2MDgzIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImczNDA1IgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjEiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii05IgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOSIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9ImZhbHNlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1nbG9iYWw9ImZhbHNlIgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMjk5MCIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8ZwogICAgICAgaWQ9ImczNDA1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4xMzY5MzY1LDAsMCwwLjEzNjkzNjUsLTIyMi4yMTc1NCwtMjAzLjM2NTEyKSI+CiAgICAgIDxnCiAgICAgICAgIGlkPSJnMzE2MCIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoNy4zMDI2NTQ5LDAsMCw3LjMwMjY1NDksMTc2OC4zNTY3LDE2MzEuMDcyMSkiPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgaWQ9InBhdGgzMTYyIgogICAgICAgICAgIGQ9Im0gMTUuNTkwNTUxLDExLjc2Mzc4IDcuOTM3MDA4LDExLjY1NzQ4IC02LjEyOTkyMSwwIC01LjM1MDM5NCwtNy43OTUyNzUgLTUuMjc5NTI3NSw3Ljc5NTI3NSAtNi4xNjUzNTQzLDAgNy45MDE1NzQ3LC0xMS42NTc0OCAtNy42MTgxMTAxNCwtMTEuMTYxNDE3NzggNi4xNjUzNTQyNCwwIDQuOTk2MDYzLDcuMzM0NjQ1NzggNC45OTYwNjMsLTcuMzM0NjQ1NzggNi4xNjUzNTQsMCB6IgogICAgICAgICAgIHN0eWxlPSJmaWxsOiNmZjAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOiNkNDAwMDA7c3Ryb2tlLXdpZHRoOjEuMTY5MjkxMzhweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgIDwvZz4KICAgICAgPGcKICAgICAgICAgaWQ9ImcyOTk1IgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMSwwLDAsMSwzNzE5Ljk2NDksLTMuMjQyMDg1NSkiPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJzc3NjY2NjY3Nzc2NjcyIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQyOTk5KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MTQuNjA1MzEwNDQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIgogICAgICAgICAgIGQ9Im0gMTY4MS4xOTIyLDE3OTIuNTc3IGMgMjkuNzUxOCwxMDEuOTIxIDEzNS41NjY5LDE2MC4xODE5IDIzNi4xOTgyLDEzMC4wNDg5IDEwMC42MzEyLC0zMC4xMzMxIDE1OC4xNTUxLC0xMzcuMzA0MSAxMjguNDAzNCwtMjM5LjIyNSAtMTUuNjc5MywtNTMuNzEyNCAtNTIuNDc5NSwtOTUuMjg5OSAtOTguNTE0NCwtMTE4LjIwMSBsIDIyLjQ5MDYsLTUxLjcwMjUgLTE3OS43NTI2LDkuMzgyNyA5NS42Njc0LDE1OS4yMjIxIDMzLjI4NywtNTEuODY2MiBjIDI4LjkxNjcsMTUuMTM1NCA1MS45NDM4LDQxLjcwNzEgNjEuODk1Myw3NS43OTc3IDE5LjM3NCw2Ni4zNjk5IC0xOC4wNzk3LDEzNi4xNDkzIC04My42MTAxLDE1NS43NzE2IC02NS41MzA0LDE5LjYyMjMgLTEzNC40NTYyLC0xOC4zMDI2IC0xNTMuODMwMywtODQuNjcyNiAtNS41NDMzLC0xOC45OTAyIC02LjQxNDcsLTM4LjI0NjkgLTMuMzIzNSwtNTYuNTQxNCBsIC02My45MzIxLC0xNS4zNzE3IGMgLTQuODQ5NiwyOC4yNTE0IC0zLjU0NSw1OC4wMTI0IDUuMDIxMSw4Ny4zNTc0IHoiCiAgICAgICAgICAgaWQ9InBhdGgyMzk2IiAvPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJzc3NjY2NjY3NzY2NjcyIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjE0LjYwNTMwOTQ5O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIKICAgICAgICAgICBkPSJtIDE2OTcuMDczNywxNzkzLjAxNDkgYyAyMS45MDI2LDc1LjgwNjYgOTYuMTMzMiwxMjEuODQ4MiAxNzMuNDc2OSwxMjMuMjE4NyAxMTIuMTQ1NSwxLjk4NzIgMTY5LjQwMjIsLTExMy4wMDMgMTY5Ljc2OTIsLTE3My40MjA0IDAuNjM0LC0xMDQuMzc3IC03Ni4wMjI4LC0xNTUuMDQ0OCAtMTExLjMyMTQsLTE3Mi4yNDk4IGwgMTYuNTQxMiwtMzguNTkwOSAtMTI5LjYwNjUsNS4xOTAyIDY5LjgyNywxMTYuNzM2IDI3LjE2NTksLTQ0LjgyNDQgYyA2OS4yNzQ1LDQyLjUzNDcgODcuNDU3Myw4Mi4xNTc0IDg4LjIzMTQsMTM0LjgwMTggMC43OTIxLDUzLjg2OTkgLTQyLjY2MzcsMTMzLjk3OTUgLTEzMy40MzA5LDEzNy42Mzg3IC03OC4xNjQyLDMuMTUxMSAtMTIzLjAxNDMsLTUyLjkxMzEgLTEzNy44NywtMTAyLjc1MzIgLTYuNTc0LC0xNi4yNTIyIC02LjU3ODMsLTMzLjM2ODMgLTYuMTk5NywtNDcuMTA2NSBsIC0zNS42NjExLC04LjYzODggYyAtMS4wNjMxLDIxLjU0NzIgMi40MzAxLDQ2Ljk4OTMgOS4wNzgsNjkuOTk4NiB6IgogICAgICAgICAgIGlkPSJwYXRoMjM5Ni05IiAvPgogICAgICA8L2c+CiAgICA8L2c+CiAgPC9nPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTUzMjQiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlIC8+CiAgICAgICAgPGNjOmxpY2Vuc2UKICAgICAgICAgICByZGY6cmVzb3VyY2U9IiIgLz4KICAgICAgICA8ZGM6ZGF0ZT5Nb24gT2N0IDEwIDEzOjQ0OjUyIDIwMTEgKzAwMDA8L2RjOmRhdGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9EcmFmdC9SZXNvdXJjZXMvaWNvbnMvRHJhZnRfUm90YXRlLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bYWdyeXNvbl0gQWxleGFuZGVyIEdyeXNvbjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgICAgPGRjOmRlc2NyaXB0aW9uPkFuIGFycm93IGluIGEgY2lyY3VsYXIgc2hhcGUgd2l0aCB0aGUgaGVhZCBjdXJ2aW5nIHRvd2FyZHMgdGhlIHRhaWw8L2RjOmRlc2NyaXB0aW9uPgogICAgICAgIDxkYzpzdWJqZWN0PgogICAgICAgICAgPHJkZjpCYWc+CiAgICAgICAgICAgIDxyZGY6bGk+YXJyb3c8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5jdXJ2ZWQ8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5yZWZyZXNoPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+cm90YXRlPC9yZGY6bGk+CiAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KPC9zdmc+Cg==
"""
-rotateY_b64=\
-"""
+rotateY_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMwMDAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNCByOTkzOSIKICAgc29kaXBvZGk6ZG9jbmFtZT0icm90YXRlWS5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMzMDAyIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzM5MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMzk1IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM5NyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzOTMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzk5IgogICAgICAgeDE9IjE5NDIuNzM4MiIKICAgICAgIHkxPSIxOTM0Ljc1NiIKICAgICAgIHgyPSIxODA5LjUwMjEiCiAgICAgICB5Mj0iMTU0Ny40MTM1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjk4NjU3ODExLDAsMCwwLjk5OTIyMDc4LDM3MDYuODY1OCwtMi42ODExNjk3KSIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMDA4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzkzLTciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzk5LTEiCiAgICAgICB4MT0iMTY2OS43MzE0IgogICAgICAgeTE9IjE3MjYuMDU4NSIKICAgICAgIHgyPSIyMDY3LjE3MDIiCiAgICAgICB5Mj0iMTcyNi4wNTg1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTg2NTc4MTEsMCwwLDAuOTk5MjIwNzgsMjAuMTI5MjUxLC0yLjY4MTE2OTcpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzkzLTciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAzZGRkO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDMzOTUtNCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzYzOWVmMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMzk3LTAiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzkzLTEiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyOTk5IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTg2NTc4MTEsMCwwLDAuOTk5MjIwNzgsMjAuMTI5MjUxLC0yLjY4MTE2OTcpIgogICAgICAgeDE9IjE5NDIuNzM4MiIKICAgICAgIHkxPSIxOTM0Ljc1NiIKICAgICAgIHgyPSIxODA5LjUwMjEiCiAgICAgICB5Mj0iMTU0Ny40MTM1IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzkzLTEiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzM5NS03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM5Ny00IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjYuODUwMDk2OSIKICAgICBpbmtzY2FwZTpjeD0iLTI1LjIzNDM2OCIKICAgICBpbmtzY2FwZTpjeT0iMjkuNDY2MDgzIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImczNDA1IgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjEiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii05IgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOSIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9ImZhbHNlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1nbG9iYWw9ImZhbHNlIgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMjk5MCIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8ZwogICAgICAgaWQ9ImczNDA1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4xMzY5MzY1LDAsMCwwLjEzNjkzNjUsLTIyMi4yMTc1NCwtMjAzLjM2NTEyKSI+CiAgICAgIDx0ZXh0CiAgICAgICAgIHNvZGlwb2RpOmxpbmVzcGFjaW5nPSIxMjUlIgogICAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgICBzdHlsZT0iZm9udC1zaXplOjIyOC45NTMxMjVweDtmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDtsaW5lLWhlaWdodDoxMjUlO2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O2ZpbGw6IzAwODAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzAwNTUwMDtzdHJva2Utd2lkdGg6OC41NDQ5Njc2NTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO2Rpc3BsYXk6aW5saW5lO2ZvbnQtZmFtaWx5OkRlamFWdSBTYW5zOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246RGVqYVZ1IFNhbnMgQm9sZCIKICAgICAgICAgeD0iMTc3My41NjgxIgogICAgICAgICB5PSIxODAyLjI0NDEiCiAgICAgICAgIGlkPSJ0ZXh0NDE5OSI+PHRzcGFuCiAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICBpZD0idHNwYW40MjAxIgogICAgICAgICAgIHg9IjE3NzMuNTY4MSIKICAgICAgICAgICB5PSIxODAyLjI0NDEiCiAgICAgICAgICAgc3R5bGU9InN0cm9rZTojMDA1NTAwO3N0cm9rZS13aWR0aDo4LjU0NDk2NzY1O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIj5ZPC90c3Bhbj48L3RleHQ+CiAgICAgIDxnCiAgICAgICAgIGlkPSJnMjk5NSIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTEsMCwwLDEsMzcxOS45NjQ5LC0zLjI0MjA4NTUpIj4KICAgICAgICA8cGF0aAogICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0ic3NzY2NjY2Nzc3NjY3MiCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50Mjk5OSk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjE0LjYwNTMxMDQ0O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIKICAgICAgICAgICBkPSJtIDE2ODEuMTkyMiwxNzkyLjU3NyBjIDI5Ljc1MTgsMTAxLjkyMSAxMzUuNTY2OSwxNjAuMTgxOSAyMzYuMTk4MiwxMzAuMDQ4OSAxMDAuNjMxMiwtMzAuMTMzMSAxNTguMTU1MSwtMTM3LjMwNDEgMTI4LjQwMzQsLTIzOS4yMjUgLTE1LjY3OTMsLTUzLjcxMjQgLTUyLjQ3OTUsLTk1LjI4OTkgLTk4LjUxNDQsLTExOC4yMDEgbCAyMi40OTA2LC01MS43MDI1IC0xNzkuNzUyNiw5LjM4MjcgOTUuNjY3NCwxNTkuMjIyMSAzMy4yODcsLTUxLjg2NjIgYyAyOC45MTY3LDE1LjEzNTQgNTEuOTQzOCw0MS43MDcxIDYxLjg5NTMsNzUuNzk3NyAxOS4zNzQsNjYuMzY5OSAtMTguMDc5NywxMzYuMTQ5MyAtODMuNjEwMSwxNTUuNzcxNiAtNjUuNTMwNCwxOS42MjIzIC0xMzQuNDU2MiwtMTguMzAyNiAtMTUzLjgzMDMsLTg0LjY3MjYgLTUuNTQzMywtMTguOTkwMiAtNi40MTQ3LC0zOC4yNDY5IC0zLjMyMzUsLTU2LjU0MTQgbCAtNjMuOTMyMSwtMTUuMzcxNyBjIC00Ljg0OTYsMjguMjUxNCAtMy41NDUsNTguMDEyNCA1LjAyMTEsODcuMzU3NCB6IgogICAgICAgICAgIGlkPSJwYXRoMjM5NiIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0ic3NzY2NjY2Nzc2NjY3MiCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoxNC42MDUzMDk0OTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiCiAgICAgICAgICAgZD0ibSAxNjk3LjA3MzcsMTc5My4wMTQ5IGMgMjEuOTAyNiw3NS44MDY2IDk2LjEzMzIsMTIxLjg0ODIgMTczLjQ3NjksMTIzLjIxODcgMTEyLjE0NTUsMS45ODcyIDE2OS40MDIyLC0xMTMuMDAzIDE2OS43NjkyLC0xNzMuNDIwNCAwLjYzNCwtMTA0LjM3NyAtNzYuMDIyOCwtMTU1LjA0NDggLTExMS4zMjE0LC0xNzIuMjQ5OCBsIDE2LjU0MTIsLTM4LjU5MDkgLTEyOS42MDY1LDUuMTkwMiA2OS44MjcsMTE2LjczNiAyNy4xNjU5LC00NC44MjQ0IGMgNjkuMjc0NSw0Mi41MzQ3IDg3LjQ1NzMsODIuMTU3NCA4OC4yMzE0LDEzNC44MDE4IDAuNzkyMSw1My44Njk5IC00Mi42NjM3LDEzMy45Nzk1IC0xMzMuNDMwOSwxMzcuNjM4NyAtNzguMTY0MiwzLjE1MTEgLTEyMy4wMTQzLC01Mi45MTMxIC0xMzcuODcsLTEwMi43NTMyIC02LjU3NCwtMTYuMjUyMiAtNi41NzgzLC0zMy4zNjgzIC02LjE5OTcsLTQ3LjEwNjUgbCAtMzUuNjYxMSwtOC42Mzg4IGMgLTEuMDYzMSwyMS41NDcyIDIuNDMwMSw0Ni45ODkzIDkuMDc4LDY5Ljk5ODYgeiIKICAgICAgICAgICBpZD0icGF0aDIzOTYtOSIgLz4KICAgICAgPC9nPgogICAgPC9nPgogIDwvZz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGE1MzI0Ij4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZSAvPgogICAgICAgIDxjYzpsaWNlbnNlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSIiIC8+CiAgICAgICAgPGRjOmRhdGU+TW9uIE9jdCAxMCAxMzo0NDo1MiAyMDExICswMDAwPC9kYzpkYXRlPgogICAgICAgIDxkYzpjcmVhdG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W3dtYXllcl08L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnJpZ2h0cz4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkZyZWVDQUQgTEdQTDIrPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpyaWdodHM+CiAgICAgICAgPGRjOnB1Ymxpc2hlcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkZyZWVDQUQ8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnB1Ymxpc2hlcj4KICAgICAgICA8ZGM6aWRlbnRpZmllcj5GcmVlQ0FEL3NyYy9Nb2QvRHJhZnQvUmVzb3VyY2VzL2ljb25zL0RyYWZ0X1JvdGF0ZS5zdmc8L2RjOmlkZW50aWZpZXI+CiAgICAgICAgPGRjOnJlbGF0aW9uPmh0dHA6Ly93d3cuZnJlZWNhZHdlYi5vcmcvd2lraS9pbmRleC5waHA/dGl0bGU9QXJ0d29yazwvZGM6cmVsYXRpb24+CiAgICAgICAgPGRjOmNvbnRyaWJ1dG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2Fncnlzb25dIEFsZXhhbmRlciBHcnlzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICAgIDxkYzpkZXNjcmlwdGlvbj5BbiBhcnJvdyBpbiBhIGNpcmN1bGFyIHNoYXBlIHdpdGggdGhlIGhlYWQgY3VydmluZyB0b3dhcmRzIHRoZSB0YWlsPC9kYzpkZXNjcmlwdGlvbj4KICAgICAgICA8ZGM6c3ViamVjdD4KICAgICAgICAgIDxyZGY6QmFnPgogICAgICAgICAgICA8cmRmOmxpPmFycm93PC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+Y3VydmVkPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+cmVmcmVzaDwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPnJvdGF0ZTwvcmRmOmxpPgogICAgICAgICAgPC9yZGY6QmFnPgogICAgICAgIDwvZGM6c3ViamVjdD4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+Cjwvc3ZnPgo=
"""
-rotateZ_b64=\
-"""
+rotateZ_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMwMDAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNCByOTkzOSIKICAgc29kaXBvZGk6ZG9jbmFtZT0icm90YXRlWi5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMzMDAyIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzM5MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMzk1IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM5NyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMzOTMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzk5IgogICAgICAgeDE9IjE5NDIuNzM4MiIKICAgICAgIHkxPSIxOTM0Ljc1NiIKICAgICAgIHgyPSIxODA5LjUwMjEiCiAgICAgICB5Mj0iMTU0Ny40MTM1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjk4NjU3ODExLDAsMCwwLjk5OTIyMDc4LDM3MDYuODY1OCwtMi42ODExNjk3KSIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMDA4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzkzLTciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzk5LTEiCiAgICAgICB4MT0iMTY2OS43MzE0IgogICAgICAgeTE9IjE3MjYuMDU4NSIKICAgICAgIHgyPSIyMDY3LjE3MDIiCiAgICAgICB5Mj0iMTcyNi4wNTg1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTg2NTc4MTEsMCwwLDAuOTk5MjIwNzgsMjAuMTI5MjUxLC0yLjY4MTE2OTcpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzkzLTciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAzZGRkO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDMzOTUtNCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzYzOWVmMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMzk3LTAiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMzkzLTEiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyOTk5IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTg2NTc4MTEsMCwwLDAuOTk5MjIwNzgsMjAuMTI5MjUxLC0yLjY4MTE2OTcpIgogICAgICAgeDE9IjE5NDIuNzM4MiIKICAgICAgIHkxPSIxOTM0Ljc1NiIKICAgICAgIHgyPSIxODA5LjUwMjEiCiAgICAgICB5Mj0iMTU0Ny40MTM1IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMzkzLTEiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzM5NS03IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzM5Ny00IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjYuODUwMDk2OSIKICAgICBpbmtzY2FwZTpjeD0iLTI1LjIzNDM2OCIKICAgICBpbmtzY2FwZTpjeT0iMjkuNDY2MDgzIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImczNDA1IgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjEiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii05IgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOSIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9ImZhbHNlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1nbG9iYWw9ImZhbHNlIgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMjk5MCIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8ZwogICAgICAgaWQ9ImczNDA1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4xMzY5MzY1LDAsMCwwLjEzNjkzNjUsLTIyMi4yMTc1NCwtMjAzLjM2NTEyKSI+CiAgICAgIDx0ZXh0CiAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgIHN0eWxlPSJmb250LXNpemU6MjM1LjY2MDI5MzU4cHg7Zm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDtsaW5lLWhlaWdodDo3Ni45OTk5OTgwOSU7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3BhY2luZzowcHg7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6OC43OTUzMDQzO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7Zm9udC1mYW1pbHk6U2FuczstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOlNhbnMgQm9sZCIKICAgICAgICAgeD0iMTc4NS40MDgyIgogICAgICAgICB5PSIxODAzLjEzNTUiCiAgICAgICAgIGlkPSJ0ZXh0NDQ5OSIKICAgICAgICAgc29kaXBvZGk6bGluZXNwYWNpbmc9Ijc2Ljk5OTk5OCUiPjx0c3BhbgogICAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgICAgaWQ9InRzcGFuNDQ5NyIKICAgICAgICAgICB4PSIxNzg1LjQwODIiCiAgICAgICAgICAgeT0iMTgwMy4xMzU1IgogICAgICAgICAgIHN0eWxlPSJmb250LXNpemU6MjM1LjY2MDI5MzU4cHg7Zm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDtsaW5lLWhlaWdodDo3Ni45OTk5OTgwOSU7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzAwMDBmZjtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6OC43OTUzMDQzO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7Zm9udC1mYW1pbHk6U2FuczstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOlNhbnMgQm9sZCI+WjwvdHNwYW4+PC90ZXh0PgogICAgICA8ZwogICAgICAgICBpZD0iZzI5OTUiCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0xLDAsMCwxLDM3MTkuOTY0OSwtMy4yNDIwODU1KSI+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9InNzc2NjY2Njc3NzY2NzIgogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDI5OTkpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoxNC42MDUzMTA0NDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiCiAgICAgICAgICAgZD0ibSAxNjgxLjE5MjIsMTc5Mi41NzcgYyAyOS43NTE4LDEwMS45MjEgMTM1LjU2NjksMTYwLjE4MTkgMjM2LjE5ODIsMTMwLjA0ODkgMTAwLjYzMTIsLTMwLjEzMzEgMTU4LjE1NTEsLTEzNy4zMDQxIDEyOC40MDM0LC0yMzkuMjI1IC0xNS42NzkzLC01My43MTI0IC01Mi40Nzk1LC05NS4yODk5IC05OC41MTQ0LC0xMTguMjAxIGwgMjIuNDkwNiwtNTEuNzAyNSAtMTc5Ljc1MjYsOS4zODI3IDk1LjY2NzQsMTU5LjIyMjEgMzMuMjg3LC01MS44NjYyIGMgMjguOTE2NywxNS4xMzU0IDUxLjk0MzgsNDEuNzA3MSA2MS44OTUzLDc1Ljc5NzcgMTkuMzc0LDY2LjM2OTkgLTE4LjA3OTcsMTM2LjE0OTMgLTgzLjYxMDEsMTU1Ljc3MTYgLTY1LjUzMDQsMTkuNjIyMyAtMTM0LjQ1NjIsLTE4LjMwMjYgLTE1My44MzAzLC04NC42NzI2IC01LjU0MzMsLTE4Ljk5MDIgLTYuNDE0NywtMzguMjQ2OSAtMy4zMjM1LC01Ni41NDE0IGwgLTYzLjkzMjEsLTE1LjM3MTcgYyAtNC44NDk2LDI4LjI1MTQgLTMuNTQ1LDU4LjAxMjQgNS4wMjExLDg3LjM1NzQgeiIKICAgICAgICAgICBpZD0icGF0aDIzOTYiIC8+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9InNzc2NjY2Njc3NjY2NzIgogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MTQuNjA1MzA5NDk7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIgogICAgICAgICAgIGQ9Im0gMTY5Ny4wNzM3LDE3OTMuMDE0OSBjIDIxLjkwMjYsNzUuODA2NiA5Ni4xMzMyLDEyMS44NDgyIDE3My40NzY5LDEyMy4yMTg3IDExMi4xNDU1LDEuOTg3MiAxNjkuNDAyMiwtMTEzLjAwMyAxNjkuNzY5MiwtMTczLjQyMDQgMC42MzQsLTEwNC4zNzcgLTc2LjAyMjgsLTE1NS4wNDQ4IC0xMTEuMzIxNCwtMTcyLjI0OTggbCAxNi41NDEyLC0zOC41OTA5IC0xMjkuNjA2NSw1LjE5MDIgNjkuODI3LDExNi43MzYgMjcuMTY1OSwtNDQuODI0NCBjIDY5LjI3NDUsNDIuNTM0NyA4Ny40NTczLDgyLjE1NzQgODguMjMxNCwxMzQuODAxOCAwLjc5MjEsNTMuODY5OSAtNDIuNjYzNywxMzMuOTc5NSAtMTMzLjQzMDksMTM3LjYzODcgLTc4LjE2NDIsMy4xNTExIC0xMjMuMDE0MywtNTIuOTEzMSAtMTM3Ljg3LC0xMDIuNzUzMiAtNi41NzQsLTE2LjI1MjIgLTYuNTc4MywtMzMuMzY4MyAtNi4xOTk3LC00Ny4xMDY1IGwgLTM1LjY2MTEsLTguNjM4OCBjIC0xLjA2MzEsMjEuNTQ3MiAyLjQzMDEsNDYuOTg5MyA5LjA3OCw2OS45OTg2IHoiCiAgICAgICAgICAgaWQ9InBhdGgyMzk2LTkiIC8+CiAgICAgIDwvZz4KICAgIDwvZz4KICA8L2c+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhNTMyNCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGUgLz4KICAgICAgICA8Y2M6bGljZW5zZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iIiAvPgogICAgICAgIDxkYzpkYXRlPk1vbiBPY3QgMTAgMTM6NDQ6NTIgMjAxMSArMDAwMDwvZGM6ZGF0ZT4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlt3bWF5ZXJdPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjcmVhdG9yPgogICAgICAgIDxkYzpyaWdodHM+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEIExHUEwyKzwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cmlnaHRzPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL0RyYWZ0L1Jlc291cmNlcy9pY29ucy9EcmFmdF9Sb3RhdGUuc3ZnPC9kYzppZGVudGlmaWVyPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgICA8ZGM6ZGVzY3JpcHRpb24+QW4gYXJyb3cgaW4gYSBjaXJjdWxhciBzaGFwZSB3aXRoIHRoZSBoZWFkIGN1cnZpbmcgdG93YXJkcyB0aGUgdGFpbDwvZGM6ZGVzY3JpcHRpb24+CiAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICA8cmRmOkJhZz4KICAgICAgICAgICAgPHJkZjpsaT5hcnJvdzwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmN1cnZlZDwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPnJlZnJlc2g8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5yb3RhdGU8L3JkZjpsaT4KICAgICAgICAgIDwvcmRmOkJhZz4KICAgICAgICA8L2RjOnN1YmplY3Q+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgo8L3N2Zz4K
"""
-putX_b64=\
-"""
+putX_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI2ODIiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNCByOTkzOSIKICAgc29kaXBvZGk6ZG9jbmFtZT0icHV0WC5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMyNjg0Ij4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzU5MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNjOGUwZjk7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzU5NSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzYzN2RjYTtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNTk3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzU5MyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMzNTQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN4PSIzMzAuNjM3OTEiCiAgICAgICBjeT0iMzkuOTYyNzA0IgogICAgICAgZng9IjMzMC42Mzc5MSIKICAgICAgIGZ5PSIzOS45NjI3MDQiCiAgICAgICByPSIxOS41NzE0MjgiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTMyNzY2MywwLDAsMC45MzI3NjYzLC0yOTguMTU2NTEsOC4xOTEzMzgxKSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2NCI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2NiIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODY4IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUyNjkwIiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODY0IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MjQwMSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk1OTMzNywwLjA1MTc5OTk0LDAsMC43MzUyMzI1LC0yOS42MTA5MDgsLTEuMjMxNDEzKSIKICAgICAgIGN4PSI1MS4xMDU0OTkiCiAgICAgICBjeT0iMjMuODA3NDA3IgogICAgICAgZng9IjUxLjEwNTQ5OSIKICAgICAgIGZ5PSIyMy44MDc0MDciCiAgICAgICByPSIxOS41NzE0MjgiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4NjQiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQyNDA0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuMjk5MzY3MSwtMS41NzU3MjU4ZS0yLDguNDE2MTA0NGUtMywwLjk4NTA5NzksLTk0LjM1NDIwOCwtMTAuOTk4Mzg3KSIKICAgICAgIGN4PSI0OC4yODgwNjciCiAgICAgICBjeT0iNDYuNzQ2MTQiCiAgICAgICBmeD0iNDguMjg4MDY3IgogICAgICAgZnk9IjQ2Ljc0NjE0IgogICAgICAgcj0iMTkuNTcxNDI4IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzNTkzIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzM3NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjkzMjc2NjMsMCwwLDAuOTMyNzY2MywtMjY3LjE2MzIzLDEyLjUxNTk4MSkiCiAgICAgICBjeD0iMzE3LjY4MTczIgogICAgICAgY3k9IjM1LjIyNzI3NiIKICAgICAgIGZ4PSIzMTcuNjgxNzMiCiAgICAgICBmeT0iMzUuMjI3Mjc2IgogICAgICAgcj0iMTkuNTcxNDI4IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODY0LTciCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQyNDA0LTEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi4yOTkzNjcxLC0wLjAxNTc1NzI2LDAuMDA4NDE2MSwwLjk4NTA5NzksLTk0LjM1NDIwOCwtMTAuOTk4Mzg3KSIKICAgICAgIGN4PSI0OC4yODgwNjciCiAgICAgICBjeT0iNDYuNzQ2MTQiCiAgICAgICBmeD0iNDguMjg4MDY3IgogICAgICAgZnk9IjQ2Ljc0NjE0IgogICAgICAgcj0iMTkuNTcxNDI4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODY0LTciPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4NjYtNCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODY4LTAiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMjc5NTtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICByPSIxOS41NzE0MjgiCiAgICAgICBmeT0iNDYuNzQ2MTQiCiAgICAgICBmeD0iNDguMjg4MDY3IgogICAgICAgY3k9IjQ2Ljc0NjE0IgogICAgICAgY3g9IjQ4LjI4ODA2NyIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi4yOTkzNjcxLC0wLjAxNTc1NzI2LDAuMDA4NDE2MSwwLjk4NTA5NzksLTk0Ljg2Nzg0NSw2Ljg5MzE4MSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMwMTQiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODY0LTciCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0icm90YXRlKDg5Ljg2Mjk0MiwxMi4wMzU5MjQsLTEyLjExMDE2OCkiCiAgICAgICB4MT0iNTEuOTczODI3IgogICAgICAgeTE9IjM1Ljk3ODQxNiIKICAgICAgIHgyPSIzMy45ODU4NCIKICAgICAgIHkyPSIzMC45MzUzNzciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI5LjY4NzUiCiAgICAgaW5rc2NhcGU6Y3g9IjMyIgogICAgIGlua3NjYXBlOmN5PSIzMiIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJnMzM4MSIKICAgICBzaG93Z3JpZD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMjU2MCIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMzYxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOSIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTkiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDQwIgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTI2ODciPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6dGl0bGUgLz4KICAgICAgICA8ZGM6ZGF0ZT4yMDEyLTExLTI1PC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL1BhcnQvR3VpL1Jlc291cmNlcy9pY29ucy9QYXJ0X09mZnNldC5zdmc8L2RjOmlkZW50aWZpZXI+CiAgICAgICAgPGRjOnJpZ2h0cz4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkZyZWVDQUQgTEdQTDIrPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpyaWdodHM+CiAgICAgICAgPGNjOmxpY2Vuc2U+aHR0cHM6Ly93d3cuZ251Lm9yZy9jb3B5bGVmdC9sZXNzZXIuaHRtbDwvY2M6bGljZW5zZT4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bYWdyeXNvbl0gQWxleGFuZGVyIEdyeXNvbjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIj4KICAgIDxnCiAgICAgICBpZD0iZzMzODEiPgogICAgICA8cGF0aAogICAgICAgICBzdHlsZT0iZmlsbDojODA4MDAwO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoxLjQ1Mzg0NjE7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0iTSAyLjIsNDUuOTA3NjkyIDE2LjczODQ2MiwzOC42Mzg0NjIgNDAsNDAuMDkyMzA4IDI1LjQ2MTUzOCw0Ny4zNjE1MzggWiIKICAgICAgICAgaWQ9InBhdGgzMDI3IgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIiAvPgogICAgICA8ZwogICAgICAgICBpZD0iZzM4MzMiCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEsLTAuMDU4ODIzNTMsMCwxLDUwLjQ1Njk5LDQuNTg5MzI4OCkiPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIgogICAgICAgICAgIGlkPSJwYXRoMzM0MyIKICAgICAgICAgICBkPSJtIC0xNC45NTY5ODgsMTguOTQyNjUzIGggLTEwIGwgMTBlLTcsLTE0IGggLTE0LjAwMDAwMSB2IDE0IGggLTEwIGwgMTcsMTggeiIKICAgICAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzgzNyk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIgogICAgICAgICAgIGlkPSJwYXRoMzM0My0yIgogICAgICAgICAgIGQ9Im0gLTE5LjYzODI4MiwyMC45NDI2NTMgaCAtNy4zMTg3MDYgbCAtMWUtNiwtMTQgaCAtOS45OTk5OTkgdiAxNCBoIC03LjM5NTI2MSBsIDEyLjM5NTI2MSwxMyB6IgogICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgICA8L2c+CiAgICAgIDxwYXRoCiAgICAgICAgIHN0eWxlPSJmaWxsOiM3MjlmY2Y7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0ibSAyLjIsNTkgMjAsLTEwIDMyLDIgLTIwLDEwIHoiCiAgICAgICAgIGlkPSJwYXRoMzAyNy0zIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIiAvPgogICAgICA8ZwogICAgICAgICBpZD0iZzMxNjAiCiAgICAgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDM4LjIwNjE4LDIuMDc2NTc0KSI+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBpZD0icGF0aDMxNjIiCiAgICAgICAgICAgZD0ibSAxNS41OTA1NTEsMTEuNzYzNzggNy45MzcwMDgsMTEuNjU3NDggLTYuMTI5OTIxLDAgLTUuMzUwMzk0LC03Ljc5NTI3NSAtNS4yNzk1Mjc1LDcuNzk1Mjc1IC02LjE2NTM1NDMsMCA3LjkwMTU3NDcsLTExLjY1NzQ4IC03LjYxODExMDE0LC0xMS4xNjE0MTc3OCA2LjE2NTM1NDI0LDAgNC45OTYwNjMsNy4zMzQ2NDU3OCA0Ljk5NjA2MywtNy4zMzQ2NDU3OCA2LjE2NTM1NCwwIHoiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6I2Q0MDAwMDtzdHJva2Utd2lkdGg6MS4xNjkyOTEzOHB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgPC9nPgogICAgPC9nPgogIDwvZz4KPC9zdmc+Cg==
"""
-putY_b64=\
-"""
+putY_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI2ODIiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNCByOTkzOSIKICAgc29kaXBvZGk6ZG9jbmFtZT0icHV0WC5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMyNjg0Ij4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzU5MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNjOGUwZjk7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzU5NSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzYzN2RjYTtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNTk3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzU5MyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMzNTQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN4PSIzMzAuNjM3OTEiCiAgICAgICBjeT0iMzkuOTYyNzA0IgogICAgICAgZng9IjMzMC42Mzc5MSIKICAgICAgIGZ5PSIzOS45NjI3MDQiCiAgICAgICByPSIxOS41NzE0MjgiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTMyNzY2MywwLDAsMC45MzI3NjYzLC0yOTguMTU2NTEsOC4xOTEzMzgxKSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2NCI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2NiIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODY4IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUyNjkwIiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODY0IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MjQwMSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk1OTMzNywwLjA1MTc5OTk0LDAsMC43MzUyMzI1LC0yOS42MTA5MDgsLTEuMjMxNDEzKSIKICAgICAgIGN4PSI1MS4xMDU0OTkiCiAgICAgICBjeT0iMjMuODA3NDA3IgogICAgICAgZng9IjUxLjEwNTQ5OSIKICAgICAgIGZ5PSIyMy44MDc0MDciCiAgICAgICByPSIxOS41NzE0MjgiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4NjQiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQyNDA0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuMjk5MzY3MSwtMS41NzU3MjU4ZS0yLDguNDE2MTA0NGUtMywwLjk4NTA5NzksLTk0LjM1NDIwOCwtMTAuOTk4Mzg3KSIKICAgICAgIGN4PSI0OC4yODgwNjciCiAgICAgICBjeT0iNDYuNzQ2MTQiCiAgICAgICBmeD0iNDguMjg4MDY3IgogICAgICAgZnk9IjQ2Ljc0NjE0IgogICAgICAgcj0iMTkuNTcxNDI4IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzNTkzIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzM3NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjkzMjc2NjMsMCwwLDAuOTMyNzY2MywtMjY3LjE2MzIzLDEyLjUxNTk4MSkiCiAgICAgICBjeD0iMzE3LjY4MTczIgogICAgICAgY3k9IjM1LjIyNzI3NiIKICAgICAgIGZ4PSIzMTcuNjgxNzMiCiAgICAgICBmeT0iMzUuMjI3Mjc2IgogICAgICAgcj0iMTkuNTcxNDI4IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODY0LTciCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQyNDA0LTEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi4yOTkzNjcxLC0wLjAxNTc1NzI2LDAuMDA4NDE2MSwwLjk4NTA5NzksLTk0LjM1NDIwOCwtMTAuOTk4Mzg3KSIKICAgICAgIGN4PSI0OC4yODgwNjciCiAgICAgICBjeT0iNDYuNzQ2MTQiCiAgICAgICBmeD0iNDguMjg4MDY3IgogICAgICAgZnk9IjQ2Ljc0NjE0IgogICAgICAgcj0iMTkuNTcxNDI4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODY0LTciPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4NjYtNCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODY4LTAiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMjc5NTtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICByPSIxOS41NzE0MjgiCiAgICAgICBmeT0iNDYuNzQ2MTQiCiAgICAgICBmeD0iNDguMjg4MDY3IgogICAgICAgY3k9IjQ2Ljc0NjE0IgogICAgICAgY3g9IjQ4LjI4ODA2NyIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi4yOTkzNjcxLC0wLjAxNTc1NzI2LDAuMDA4NDE2MSwwLjk4NTA5NzksLTk0Ljg2Nzg0NSw2Ljg5MzE4MSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMwMTQiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODY0LTciCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0icm90YXRlKDg5Ljg2Mjk0MiwxMi4wMzU5MjQsLTEyLjExMDE2OCkiCiAgICAgICB4MT0iNTEuOTczODI3IgogICAgICAgeTE9IjM1Ljk3ODQxNiIKICAgICAgIHgyPSIzMy45ODU4NCIKICAgICAgIHkyPSIzMC45MzUzNzciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI5LjY4NzUiCiAgICAgaW5rc2NhcGU6Y3g9IjE0LjI5Njc3NCIKICAgICBpbmtzY2FwZTpjeT0iMzIiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzMzODEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjI1NjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTM2MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTkiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii05IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMzA0MCIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEyNjg3Ij4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzpjcmVhdG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W3dtYXllcl08L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgICAgPGRjOmRhdGU+MjAxMi0xMS0yNTwvZGM6ZGF0ZT4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9QYXJ0L0d1aS9SZXNvdXJjZXMvaWNvbnMvUGFydF9PZmZzZXQuc3ZnPC9kYzppZGVudGlmaWVyPgogICAgICAgIDxkYzpyaWdodHM+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEIExHUEwyKzwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cmlnaHRzPgogICAgICAgIDxjYzpsaWNlbnNlPmh0dHBzOi8vd3d3LmdudS5vcmcvY29weWxlZnQvbGVzc2VyLmh0bWw8L2NjOmxpY2Vuc2U+CiAgICAgICAgPGRjOmNvbnRyaWJ1dG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2Fncnlzb25dIEFsZXhhbmRlciBHcnlzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8ZwogICAgICAgaWQ9ImczMzgxIj4KICAgICAgPHRleHQKICAgICAgICAgc29kaXBvZGk6bGluZXNwYWNpbmc9IjEyNSUiCiAgICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICAgIHN0eWxlPSJmb250LXNpemU6MzEuMzUyMDM5MzRweDtmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDtsaW5lLWhlaWdodDoxMjUlO2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O2ZpbGw6IzAwODAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzAwNTUwMDtzdHJva2Utd2lkdGg6MS4xNzAxMTc5NztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO2Rpc3BsYXk6aW5saW5lO2ZvbnQtZmFtaWx5OkRlamFWdSBTYW5zOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246RGVqYVZ1IFNhbnMgQm9sZCIKICAgICAgICAgeD0iMzguODAwMDAzIgogICAgICAgICB5PSIyNS40OTk5OTgiCiAgICAgICAgIGlkPSJ0ZXh0NDE5OSI+PHRzcGFuCiAgICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgICBpZD0idHNwYW40MjAxIgogICAgICAgICAgIHg9IjM4LjgwMDAwMyIKICAgICAgICAgICB5PSIyNS40OTk5OTgiCiAgICAgICAgICAgc3R5bGU9InN0cm9rZTojMDA1NTAwO3N0cm9rZS13aWR0aDoxLjE3MDExNzk3O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lIj5ZPC90c3Bhbj48L3RleHQ+CiAgICAgIDxwYXRoCiAgICAgICAgIHN0eWxlPSJmaWxsOiM4MDgwMDA7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjEuNDUzODQ2MTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBkPSJNIDIuMiw0NS45MDc2OTIgMTYuNzM4NDYyLDM4LjYzODQ2MiA0MCw0MC4wOTIzMDggMjUuNDYxNTM4LDQ3LjM2MTUzOCBaIgogICAgICAgICBpZD0icGF0aDMwMjciCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICAgIDxnCiAgICAgICAgIGlkPSJnMzgzMyIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMSwtMC4wNTg4MjM1MywwLDEsNTAuNDU2OTksNC41ODkzMjg4KSI+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgICAgaWQ9InBhdGgzMzQzIgogICAgICAgICAgIGQ9Im0gLTE0Ljk1Njk4OCwxOC45NDI2NTMgaCAtMTAgbCAxMGUtNywtMTQgaCAtMTQuMDAwMDAxIHYgMTQgaCAtMTAgbCAxNywxOCB6IgogICAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzODM3KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgICAgPHBhdGgKICAgICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgICAgaWQ9InBhdGgzMzQzLTIiCiAgICAgICAgICAgZD0ibSAtMTkuNjM4MjgyLDIwLjk0MjY1MyBoIC03LjMxODcwNiBsIC0xZS02LC0xNCBoIC05Ljk5OTk5OSB2IDE0IGggLTcuMzk1MjYxIGwgMTIuMzk1MjYxLDEzIHoiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgIDwvZz4KICAgICAgPHBhdGgKICAgICAgICAgc3R5bGU9ImZpbGw6IzcyOWZjZjtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBkPSJtIDIuMiw1OSAyMCwtMTAgMzIsMiAtMjAsMTAgeiIKICAgICAgICAgaWQ9InBhdGgzMDI3LTMiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K
"""
-putZ_b64=\
-"""
+putZ_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI2ODIiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNCByOTkzOSIKICAgc29kaXBvZGk6ZG9jbmFtZT0icHV0WS5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMyNjg0Ij4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzU5MyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNjOGUwZjk7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzU5NSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzYzN2RjYTtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzNTk3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzU5MyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMzNTQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN4PSIzMzAuNjM3OTEiCiAgICAgICBjeT0iMzkuOTYyNzA0IgogICAgICAgZng9IjMzMC42Mzc5MSIKICAgICAgIGZ5PSIzOS45NjI3MDQiCiAgICAgICByPSIxOS41NzE0MjgiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTMyNzY2MywwLDAsMC45MzI3NjYzLC0yOTguMTU2NTEsOC4xOTEzMzgxKSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2NCI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2NiIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODY4IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUyNjkwIiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODY0IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MjQwMSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjk1OTMzNywwLjA1MTc5OTk0LDAsMC43MzUyMzI1LC0yOS42MTA5MDgsLTEuMjMxNDEzKSIKICAgICAgIGN4PSI1MS4xMDU0OTkiCiAgICAgICBjeT0iMjMuODA3NDA3IgogICAgICAgZng9IjUxLjEwNTQ5OSIKICAgICAgIGZ5PSIyMy44MDc0MDciCiAgICAgICByPSIxOS41NzE0MjgiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4NjQiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQyNDA0IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuMjk5MzY3MSwtMS41NzU3MjU4ZS0yLDguNDE2MTA0NGUtMywwLjk4NTA5NzksLTk0LjM1NDIwOCwtMTAuOTk4Mzg3KSIKICAgICAgIGN4PSI0OC4yODgwNjciCiAgICAgICBjeT0iNDYuNzQ2MTQiCiAgICAgICBmeD0iNDguMjg4MDY3IgogICAgICAgZnk9IjQ2Ljc0NjE0IgogICAgICAgcj0iMTkuNTcxNDI4IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzNTkzIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzM3NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjkzMjc2NjMsMCwwLDAuOTMyNzY2MywtMjY3LjE2MzIzLDEyLjUxNTk4MSkiCiAgICAgICBjeD0iMzE3LjY4MTczIgogICAgICAgY3k9IjM1LjIyNzI3NiIKICAgICAgIGZ4PSIzMTcuNjgxNzMiCiAgICAgICBmeT0iMzUuMjI3Mjc2IgogICAgICAgcj0iMTkuNTcxNDI4IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODY0LTciCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQyNDA0LTEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi4yOTkzNjcxLC0wLjAxNTc1NzI2LDAuMDA4NDE2MSwwLjk4NTA5NzksLTk0LjM1NDIwOCwtMTAuOTk4Mzg3KSIKICAgICAgIGN4PSI0OC4yODgwNjciCiAgICAgICBjeT0iNDYuNzQ2MTQiCiAgICAgICBmeD0iNDguMjg4MDY3IgogICAgICAgZnk9IjQ2Ljc0NjE0IgogICAgICAgcj0iMTkuNTcxNDI4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODY0LTciPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDM4NjYtNCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODY4LTAiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMjc5NTtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICByPSIxOS41NzE0MjgiCiAgICAgICBmeT0iNDYuNzQ2MTQiCiAgICAgICBmeD0iNDguMjg4MDY3IgogICAgICAgY3k9IjQ2Ljc0NjE0IgogICAgICAgY3g9IjQ4LjI4ODA2NyIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi4yOTkzNjcxLC0wLjAxNTc1NzI2LDAuMDA4NDE2MSwwLjk4NTA5NzksLTk0Ljg2Nzg0NSw2Ljg5MzE4MSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMwMTQiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODY0LTciCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0icm90YXRlKDg5Ljg2Mjk0MiwxMi4wMzU5MjQsLTEyLjExMDE2OCkiCiAgICAgICB4MT0iNTEuOTczODI3IgogICAgICAgeTE9IjM1Ljk3ODQxNiIKICAgICAgIHgyPSIzMy45ODU4NCIKICAgICAgIHkyPSIzMC45MzUzNzciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI5LjY4NzUiCiAgICAgaW5rc2NhcGU6Y3g9IjE0LjI5Njc3NCIKICAgICBpbmtzY2FwZTpjeT0iMzIiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzMzODEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjI1NjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTM2MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTkiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii05IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMzA0MCIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEyNjg3Ij4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzpjcmVhdG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W3dtYXllcl08L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgICAgPGRjOmRhdGU+MjAxMi0xMS0yNTwvZGM6ZGF0ZT4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9QYXJ0L0d1aS9SZXNvdXJjZXMvaWNvbnMvUGFydF9PZmZzZXQuc3ZnPC9kYzppZGVudGlmaWVyPgogICAgICAgIDxkYzpyaWdodHM+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEIExHUEwyKzwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cmlnaHRzPgogICAgICAgIDxjYzpsaWNlbnNlPmh0dHBzOi8vd3d3LmdudS5vcmcvY29weWxlZnQvbGVzc2VyLmh0bWw8L2NjOmxpY2Vuc2U+CiAgICAgICAgPGRjOmNvbnRyaWJ1dG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2Fncnlzb25dIEFsZXhhbmRlciBHcnlzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8ZwogICAgICAgaWQ9ImczMzgxIj4KICAgICAgPHBhdGgKICAgICAgICAgc3R5bGU9ImZpbGw6IzgwODAwMDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MS40NTM4NDYxO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGQ9Ik0gMi4yLDQ1LjkwNzY5MiAxNi43Mzg0NjIsMzguNjM4NDYyIDQwLDQwLjA5MjMwOCAyNS40NjE1MzgsNDcuMzYxNTM4IFoiCiAgICAgICAgIGlkPSJwYXRoMzAyNyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgICAgPGcKICAgICAgICAgaWQ9ImczODMzIgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLC0wLjA1ODgyMzUzLDAsMSw1MC40NTY5OSw0LjU4OTMyODgpIj4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjYyIKICAgICAgICAgICBpZD0icGF0aDMzNDMiCiAgICAgICAgICAgZD0ibSAtMTQuOTU2OTg4LDE4Ljk0MjY1MyBoIC0xMCBsIDEwZS03LC0xNCBoIC0xNC4wMDAwMDEgdiAxNCBoIC0xMCBsIDE3LDE4IHoiCiAgICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM4MzcpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjYyIKICAgICAgICAgICBpZD0icGF0aDMzNDMtMiIKICAgICAgICAgICBkPSJtIC0xOS42MzgyODIsMjAuOTQyNjUzIGggLTcuMzE4NzA2IGwgLTFlLTYsLTE0IGggLTkuOTk5OTk5IHYgMTQgaCAtNy4zOTUyNjEgbCAxMi4zOTUyNjEsMTMgeiIKICAgICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgPC9nPgogICAgICA8cGF0aAogICAgICAgICBzdHlsZT0iZmlsbDojNzI5ZmNmO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGQ9Im0gMi4yLDU5IDIwLC0xMCAzMiwyIC0yMCwxMCB6IgogICAgICAgICBpZD0icGF0aDMwMjctMyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgICAgPHRleHQKICAgICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgICAgc3R5bGU9ImZvbnQtc2l6ZTozMi4yNzA0OTYzN3B4O2ZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO3RleHQtYWxpZ246c3RhcnQ7bGluZS1oZWlnaHQ6NzYuOTk5OTk4MDklO2xldHRlci1zcGFjaW5nOjBweDt3b3JkLXNwYWNpbmc6MHB4O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuMjA0Mzk4MTY7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtmb250LWZhbWlseTpTYW5zOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246U2FucyBCb2xkIgogICAgICAgICB4PSI0MSIKICAgICAgICAgeT0iMjUuNjk5OTk5IgogICAgICAgICBpZD0idGV4dDQ0OTkiCiAgICAgICAgIHNvZGlwb2RpOmxpbmVzcGFjaW5nPSI3Ni45OTk5OTglIj48dHNwYW4KICAgICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICAgIGlkPSJ0c3BhbjQ0OTciCiAgICAgICAgICAgeD0iNDEiCiAgICAgICAgICAgeT0iMjUuNjk5OTk5IgogICAgICAgICAgIHN0eWxlPSJmb250LXNpemU6MzIuMjcwNDk2MzdweDtmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDt0ZXh0LWFsaWduOnN0YXJ0O2xpbmUtaGVpZ2h0Ojc2Ljk5OTk5ODA5JTt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7ZmlsbDojMDAwMGZmO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxLjIwNDM5ODE2O3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7Zm9udC1mYW1pbHk6U2FuczstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOlNhbnMgQm9sZCI+WjwvdHNwYW4+PC90ZXh0PgogICAgPC9nPgogIDwvZz4KPC9zdmc+Cg==
"""
-centerX_b64=\
-"""
+centerX_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMxMTEiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNCByOTkzOSIKICAgc29kaXBvZGk6ZG9jbmFtZT0iY2VudGVyWC5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMzMTEzIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg0MSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwNjE5YzA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg0MyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM3OWNmYjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODQ1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg0MSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDY2NTUiCiAgICAgICB4MT0iMTU1LjQ2ODc1IgogICAgICAgeTE9IjI1NDUuMjE4OCIKICAgICAgIHgyPSI3MTMuMDYyNSIKICAgICAgIHkyPSIyNTQ1LjIxODgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMiwtMikiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iNjQgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzIgOiAyMS4zMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMzExOSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLC0xLjQ1MDAwMDEsMS40NzA1ODgyLDAsLTE1LjA1ODgyLDkxLjQ1KSIKICAgICAgIHkyPSIzNi4wNzk5OTgiCiAgICAgICB4Mj0iMjEuNjg5NjUzIgogICAgICAgeTE9IjI5LjI3OTk5OSIKICAgICAgIHgxPSI1Ni4xNzI0MDkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMzYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODk3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiwyMC4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI1IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjM5LjUxNDEwMyIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5MT0iMjMuNTI2NjQ0IgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsMzUuMjA1ODgzKSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAyNS0zIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1LTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODk5LTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4MT0iNTAuMTIwNzgxIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSw1MS40NjMxOCwyMC4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDY2IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTAwIgogICAgICAgeDE9IjMwIgogICAgICAgeTE9IjYiCiAgICAgICB4Mj0iMzQiCiAgICAgICB5Mj0iNTciCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDIyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NS02LTQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNy0wIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTktNS05IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjM5LjUxNDEwMyIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5MT0iMjQuMzc5MzA5IgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDY2LTQiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAzOSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzA0MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMDQzIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjM5LjUxNDEwMyIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5MT0iMjMuNTI2NjQ0IgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsNi4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI1LTgiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTgiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUtOCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg5Ny0yIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTktNCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNTAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsNi4yMDU4ODMpIgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTUyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDUxLjQ2MzE4LDYuMjA1ODgzKSIKICAgICAgIHgxPSI1MC4xMjA3ODEiCiAgICAgICB5MT0iMjQuMzc5MzA5IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzE1NCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjMwIgogICAgICAgeTE9IjYiCiAgICAgICB4Mj0iMzQiCiAgICAgICB5Mj0iNTciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAzOCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSw1MS40NjMxOCw2LjIwNTg4MykiCiAgICAgICB4MT0iNTAuMTIwNzgxIgogICAgICAgeTE9IjI0LjM3OTMwOSIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQwIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsMTIuNTM2ODE2LDYuMjA1ODgzKSIKICAgICAgIHgxPSI0Mi43NTgwNzYiCiAgICAgICB5MT0iMjMuNTI2NjQ0IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNDEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsNi4yMDU4ODMpIgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQzIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDUxLjQ2MzE4LDYuMjA1ODgzKSIKICAgICAgIHgxPSI1MC4xMjA3ODEiCiAgICAgICB5MT0iMjQuMzc5MzA5IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0NSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjMwIgogICAgICAgeTE9IjYiCiAgICAgICB4Mj0iMzQiCiAgICAgICB5Mj0iNTciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00LTEiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQ2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDUxLjQ2MzE4LDYuMjA1ODgzKSIKICAgICAgIHgxPSI1MC4xMjA3ODEiCiAgICAgICB5MT0iMjQuMzc5MzA5IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUtNi00LTEiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNy0wLTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS01LTktNCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOC0wIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0NCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1LTgtMCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg5Ny0yLTkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS00LTQiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTgtMCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwOTgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsNi4yMDU4ODMpIgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQtMSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxMDAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTAyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQtMSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxMTAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS04LTAiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTEyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsMTIuNTM2ODE2LDYuMjA1ODgzKSIKICAgICAgIHgxPSI0Mi43NTgwNzYiCiAgICAgICB5MT0iMjMuNTI2NjQ0IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI5LjY4NzUiCiAgICAgaW5rc2NhcGU6Y3g9Ii0zLjQwNjQ1MTgiCiAgICAgaW5rc2NhcGU6Y3k9IjMyIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIKICAgICBzaG93Z3JpZD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMjU2MCIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMzYxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOSIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTkiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1nbG9iYWw9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQzMDQ2IgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMzA0OCIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIKICAgICAgIHNwYWNpbmd4PSIxNiIKICAgICAgIHNwYWNpbmd5PSIxNiIKICAgICAgIG9yaWdpbng9IjAiCiAgICAgICBvcmlnaW55PSIwIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIj4KICAgIDxnCiAgICAgICBpZD0iZzMxNjAiCiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzOC44ODc3OTUsMS45OTQwOTQzKSI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlkPSJwYXRoMzE2MiIKICAgICAgICAgZD0ibSAxNS41OTA1NTEsMTEuNzYzNzggNy45MzcwMDgsMTEuNjU3NDggLTYuMTI5OTIxLDAgLTUuMzUwMzk0LC03Ljc5NTI3NSAtNS4yNzk1Mjc1LDcuNzk1Mjc1IC02LjE2NTM1NDMsMCA3LjkwMTU3NDcsLTExLjY1NzQ4IC03LjYxODExMDE0LC0xMS4xNjE0MTc3OCA2LjE2NTM1NDI0LDAgNC45OTYwNjMsNy4zMzQ2NDU3OCA0Ljk5NjA2MywtNy4zMzQ2NDU3OCA2LjE2NTM1NCwwIHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZjAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOiNkNDAwMDA7c3Ryb2tlLXdpZHRoOjEuMTY5MjkxMzhweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPC9nPgogICAgPGcKICAgICAgIGlkPSJnMzAxNSIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDAuNzI5LDAsMTkuNTcyKSI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzA4NyIKICAgICAgICAgZD0iTSAzMiw1NiAzMiw4IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDo4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMwODctNiIKICAgICAgICAgZD0iTSAzMiw1NiAzMiw4IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTp1cmwoI2xpbmVhckdyYWRpZW50MzEwMik7c3Ryb2tlLXdpZHRoOjQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzA4Ny02LTIiCiAgICAgICAgIGQ9Ik0gMzEsNTYgMzEsOCIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgIDwvZz4KICAgIDxnCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMS4wNjEyMDgsMCwwLDEuMDYxMjA4LDEwNi4yODQ1NiwxNC4xODQ0MzIpIgogICAgICAgaWQ9ImczMDExIj4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIgogICAgICAgICBpZD0icGF0aDMzNDMiCiAgICAgICAgIGQ9Im0gNDksMTkgMCw4IC04LDAgMCwxMCA4LDAgMCw4IDEyLC0xMyB6IgogICAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzExMik7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIgogICAgICAgICBpZD0icGF0aDMzNDMtMiIKICAgICAgICAgZD0iTSA1MS4wNDA3NDgsMjQuNDg3MDIxIDUxLDI5IGwgLTgsMCAwLDYgOCwwIDAuMDE3MDUsNS4xMzA2ODIgNy4yNjQxOTEsLTguMTA2NTc2IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDwvZz4KICAgIDxnCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMS4wNjEyMDgsMCwwLDEuMDYxMjA4LDI1LjYzMjc1MiwxNC4xODQ0MzIpIgogICAgICAgaWQ9ImczMDA3Ij4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIgogICAgICAgICBpZD0icGF0aDMzNDMtMyIKICAgICAgICAgZD0ibSAxNSwxOSAwLDggOCwwIDAsMTAgLTgsMCAwLDggTCAzLDMyIHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMTEwKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoMzM0My0yLTUiCiAgICAgICAgIGQ9Ik0gMTIuOTU5MjUyLDI0LjQ4NzAyMSAxMywyOSBsIDgsMCAwLDYgLTgsMCAtMC4wMTcwNSw1LjEzMDY4MiAtNy4yNjQxOTEsLTguMTA2NTc2IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDwvZz4KICA8L2c+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhNTc4MSI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGUgLz4KICAgICAgICA8Y2M6bGljZW5zZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iIiAvPgogICAgICAgIDxkYzpkYXRlPk1vbiBPY3QgMTAgMTM6NDQ6NTIgMjAxMSArMDAwMDwvZGM6ZGF0ZT4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlt3bWF5ZXJdPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjcmVhdG9yPgogICAgICAgIDxkYzpyaWdodHM+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEIExHUEwyKzwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cmlnaHRzPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL0RyYWZ0L1Jlc291cmNlcy9pY29ucy9EcmFmdF9UcmltZXguc3ZnPC9kYzppZGVudGlmaWVyPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgICA8ZGM6c3ViamVjdD4KICAgICAgICAgIDxyZGY6QmFnPgogICAgICAgICAgICA8cmRmOmxpPmFycm93PC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+YXJyb3dzPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+bGluZTwvcmRmOmxpPgogICAgICAgICAgPC9yZGY6QmFnPgogICAgICAgIDwvZGM6c3ViamVjdD4KICAgICAgICA8ZGM6ZGVzY3JpcHRpb24+QSB2ZXJ0aWNhbCBsaW5lIHdpdGggYW4gYXJyb3cgcG9pbnRpbmcgYXdheSBmcm9tIGl0IG9uIGVhY2ggc2lkZTwvZGM6ZGVzY3JpcHRpb24+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgo8L3N2Zz4K
"""
-centerY_b64=\
-"""
+centerY_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMxMTEiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNCByOTkzOSIKICAgc29kaXBvZGk6ZG9jbmFtZT0iY2VudGVyWi5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMzMTEzIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg0MSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwNjE5YzA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg0MyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM3OWNmYjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODQ1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg0MSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDY2NTUiCiAgICAgICB4MT0iMTU1LjQ2ODc1IgogICAgICAgeTE9IjI1NDUuMjE4OCIKICAgICAgIHgyPSI3MTMuMDYyNSIKICAgICAgIHkyPSIyNTQ1LjIxODgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMiwtMikiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iNjQgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzIgOiAyMS4zMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMzExOSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLC0xLjQ1MDAwMDEsMS40NzA1ODgyLDAsLTE1LjA1ODgyLDkxLjQ1KSIKICAgICAgIHkyPSIzNi4wNzk5OTgiCiAgICAgICB4Mj0iMjEuNjg5NjUzIgogICAgICAgeTE9IjI5LjI3OTk5OSIKICAgICAgIHgxPSI1Ni4xNzI0MDkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMzYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODk3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiwyMC4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI1IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjM5LjUxNDEwMyIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5MT0iMjMuNTI2NjQ0IgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsMzUuMjA1ODgzKSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAyNS0zIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1LTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODk5LTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4MT0iNTAuMTIwNzgxIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSw1MS40NjMxOCwyMC4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDY2IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTAwIgogICAgICAgeDE9IjMwIgogICAgICAgeTE9IjYiCiAgICAgICB4Mj0iMzQiCiAgICAgICB5Mj0iNTciCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDIyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NS02LTQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNy0wIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTktNS05IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjM5LjUxNDEwMyIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5MT0iMjQuMzc5MzA5IgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDY2LTQiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAzOSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzA0MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMDQzIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjM5LjUxNDEwMyIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5MT0iMjMuNTI2NjQ0IgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsNi4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI1LTgiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTgiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUtOCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg5Ny0yIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTktNCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNTAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsNi4yMDU4ODMpIgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTUyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDUxLjQ2MzE4LDYuMjA1ODgzKSIKICAgICAgIHgxPSI1MC4xMjA3ODEiCiAgICAgICB5MT0iMjQuMzc5MzA5IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzE1NCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjMwIgogICAgICAgeTE9IjYiCiAgICAgICB4Mj0iMzQiCiAgICAgICB5Mj0iNTciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAzOCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSw1MS40NjMxOCw2LjIwNTg4MykiCiAgICAgICB4MT0iNTAuMTIwNzgxIgogICAgICAgeTE9IjI0LjM3OTMwOSIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQwIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsMTIuNTM2ODE2LDYuMjA1ODgzKSIKICAgICAgIHgxPSI0Mi43NTgwNzYiCiAgICAgICB5MT0iMjMuNTI2NjQ0IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNDEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsNi4yMDU4ODMpIgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQzIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDUxLjQ2MzE4LDYuMjA1ODgzKSIKICAgICAgIHgxPSI1MC4xMjA3ODEiCiAgICAgICB5MT0iMjQuMzc5MzA5IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0NSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjMwIgogICAgICAgeTE9IjYiCiAgICAgICB4Mj0iMzQiCiAgICAgICB5Mj0iNTciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00LTEiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQ2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDUxLjQ2MzE4LDYuMjA1ODgzKSIKICAgICAgIHgxPSI1MC4xMjA3ODEiCiAgICAgICB5MT0iMjQuMzc5MzA5IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUtNi00LTEiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNy0wLTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS01LTktNCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOC0wIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0NCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1LTgtMCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg5Ny0yLTkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS00LTQiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTgtMCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwOTgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsNi4yMDU4ODMpIgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQtMSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxMDAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTAyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQtMSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxMTAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS04LTAiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTEyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsMTIuNTM2ODE2LDYuMjA1ODgzKSIKICAgICAgIHgxPSI0Mi43NTgwNzYiCiAgICAgICB5MT0iMjMuNTI2NjQ0IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI5LjY4NzUiCiAgICAgaW5rc2NhcGU6Y3g9Ii0zLjQwNjQ1MTgiCiAgICAgaW5rc2NhcGU6Y3k9IjMyIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIKICAgICBzaG93Z3JpZD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMjU2MCIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMzYxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOSIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTkiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1nbG9iYWw9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBzaG93Z3VpZGVzPSJ0cnVlIgogICAgIGlua3NjYXBlOmd1aWRlLWJib3g9InRydWUiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMzA0NiIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDMwNDgiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiCiAgICAgICBzcGFjaW5neD0iMTYiCiAgICAgICBzcGFjaW5neT0iMTYiCiAgICAgICBvcmlnaW54PSIwIgogICAgICAgb3JpZ2lueT0iMCIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8dGV4dAogICAgICAgc29kaXBvZGk6bGluZXNwYWNpbmc9IjEyNSUiCiAgICAgICB4bWw6c3BhY2U9InByZXNlcnZlIgogICAgICAgc3R5bGU9ImZvbnQtc2l6ZTozMS4zNTIwMzkzNHB4O2ZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO2xpbmUtaGVpZ2h0OjEyNSU7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3BhY2luZzowcHg7ZmlsbDojMDA4MDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMDA1NTAwO3N0cm9rZS13aWR0aDoxLjE3MDExNzk3O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7ZGlzcGxheTppbmxpbmU7Zm9udC1mYW1pbHk6RGVqYVZ1IFNhbnM7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpEZWphVnUgU2FucyBCb2xkIgogICAgICAgeD0iMzkuNjA2MTEiCiAgICAgICB5PSIyNS40NDA4MTkiCiAgICAgICBpZD0idGV4dDQxOTkiPjx0c3BhbgogICAgICAgICBzb2RpcG9kaTpyb2xlPSJsaW5lIgogICAgICAgICBpZD0idHNwYW40MjAxIgogICAgICAgICB4PSIzOS42MDYxMSIKICAgICAgICAgeT0iMjUuNDQwODE5IgogICAgICAgICBzdHlsZT0ic3Ryb2tlOiMwMDU1MDA7c3Ryb2tlLXdpZHRoOjEuMTcwMTE3OTc7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiPlk8L3RzcGFuPjwvdGV4dD4KICAgIDxnCiAgICAgICBpZD0iZzMwMTUiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwwLjcyOSwwLDE5LjU3MikiPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMwODciCiAgICAgICAgIGQ9Ik0gMzIsNTYgMzIsOCIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6ODtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMDg3LTYiCiAgICAgICAgIGQ9Ik0gMzIsNTYgMzIsOCIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6dXJsKCNsaW5lYXJHcmFkaWVudDMxMDIpO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBpZD0icGF0aDMwODctNi0yIgogICAgICAgICBkPSJNIDMxLDU2IDMxLDgiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICA8L2c+CiAgICA8ZwogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTEuMDYxMjA4LDAsMCwxLjA2MTIwOCwxMDYuMjg0NTYsMTQuMTg0NDMyKSIKICAgICAgIGlkPSJnMzAxMSI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjYyIKICAgICAgICAgaWQ9InBhdGgzMzQzIgogICAgICAgICBkPSJtIDQ5LDE5IDAsOCAtOCwwIDAsMTAgOCwwIDAsOCAxMiwtMTMgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMxMTIpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoxLjk5OTk5OTg4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjYyIKICAgICAgICAgaWQ9InBhdGgzMzQzLTIiCiAgICAgICAgIGQ9Ik0gNTEuMDQwNzQ4LDI0LjQ4NzAyMSA1MSwyOSBsIC04LDAgMCw2IDgsMCAwLjAxNzA1LDUuMTMwNjgyIDcuMjY0MTkxLC04LjEwNjU3NiB6IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoxLjk5OTk5OTg4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2c+CiAgICA8ZwogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoLTEuMDYxMjA4LDAsMCwxLjA2MTIwOCwyNS42MzI3NTIsMTQuMTg0NDMyKSIKICAgICAgIGlkPSJnMzAwNyI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjYyIKICAgICAgICAgaWQ9InBhdGgzMzQzLTMiCiAgICAgICAgIGQ9Im0gMTUsMTkgMCw4IDgsMCAwLDEwIC04LDAgMCw4IEwgMywzMiB6IgogICAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzExMCk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjQuMTY4Mzg5OCIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL2NoYW5nZXByb3AucG5nIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIgogICAgICAgICBpZD0icGF0aDMzNDMtMi01IgogICAgICAgICBkPSJNIDEyLjk1OTI1MiwyNC40ODcwMjEgMTMsMjkgbCA4LDAgMCw2IC04LDAgLTAuMDE3MDUsNS4xMzA2ODIgLTcuMjY0MTkxLC04LjEwNjU3NiB6IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoxLjk5OTk5OTg4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8L2c+CiAgPC9nPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTU3ODEiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgICAgPGNjOmxpY2Vuc2UKICAgICAgICAgICByZGY6cmVzb3VyY2U9IiIgLz4KICAgICAgICA8ZGM6ZGF0ZT5Nb24gT2N0IDEwIDEzOjQ0OjUyIDIwMTEgKzAwMDA8L2RjOmRhdGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9EcmFmdC9SZXNvdXJjZXMvaWNvbnMvRHJhZnRfVHJpbWV4LnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bYWdyeXNvbl0gQWxleGFuZGVyIEdyeXNvbjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICA8cmRmOkJhZz4KICAgICAgICAgICAgPHJkZjpsaT5hcnJvdzwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmFycm93czwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmxpbmU8L3JkZjpsaT4KICAgICAgICAgIDwvcmRmOkJhZz4KICAgICAgICA8L2RjOnN1YmplY3Q+CiAgICAgICAgPGRjOmRlc2NyaXB0aW9uPkEgdmVydGljYWwgbGluZSB3aXRoIGFuIGFycm93IHBvaW50aW5nIGF3YXkgZnJvbSBpdCBvbiBlYWNoIHNpZGU8L2RjOmRlc2NyaXB0aW9uPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KPC9zdmc+Cg==
"""
-centerZ_b64=\
-"""
+centerZ_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzMxMTEiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuNDguNCByOTkzOSIKICAgc29kaXBvZGk6ZG9jbmFtZT0iY2VudGVyWC5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMzMTEzIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg0MSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwNjE5YzA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg0MyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM3OWNmYjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODQ1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg0MSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDY2NTUiCiAgICAgICB4MT0iMTU1LjQ2ODc1IgogICAgICAgeTE9IjI1NDUuMjE4OCIKICAgICAgIHgyPSI3MTMuMDYyNSIKICAgICAgIHkyPSIyNTQ1LjIxODgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoMiwtMikiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iNjQgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzIgOiAyMS4zMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMzExOSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLC0xLjQ1MDAwMDEsMS40NzA1ODgyLDAsLTE1LjA1ODgyLDkxLjQ1KSIKICAgICAgIHkyPSIzNi4wNzk5OTgiCiAgICAgICB4Mj0iMjEuNjg5NjUzIgogICAgICAgeTE9IjI5LjI3OTk5OSIKICAgICAgIHgxPSI1Ni4xNzI0MDkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwMzYiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODk3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiwyMC4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI1IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NSIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjM5LjUxNDEwMyIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5MT0iMjMuNTI2NjQ0IgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsMzUuMjA1ODgzKSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAyNS0zIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1LTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODk5LTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICB5Mj0iMzkuNTE0MTAzIgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4MT0iNTAuMTIwNzgxIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSw1MS40NjMxOCwyMC4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDY2IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzOTAwIgogICAgICAgeDE9IjMwIgogICAgICAgeTE9IjYiCiAgICAgICB4Mj0iMzQiCiAgICAgICB5Mj0iNTciCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDIyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg5NS02LTQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNy0wIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTktNS05IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjM5LjUxNDEwMyIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5MT0iMjQuMzc5MzA5IgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDY2LTQiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTYtNCIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAzOSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzA0MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzIwNGE4NztzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMDQzIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjM5LjUxNDEwMyIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5MT0iMjMuNTI2NjQ0IgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsNi4yMDU4ODMpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDI1LTgiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTgiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUtOCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg5Ny0yIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMjA0YTg3O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4OTktNCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxNTAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsNi4yMDU4ODMpIgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTUyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDUxLjQ2MzE4LDYuMjA1ODgzKSIKICAgICAgIHgxPSI1MC4xMjA3ODEiCiAgICAgICB5MT0iMjQuMzc5MzA5IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzE1NCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjMwIgogICAgICAgeTE9IjYiCiAgICAgICB4Mj0iMzQiCiAgICAgICB5Mj0iNTciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzAzOCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSw1MS40NjMxOCw2LjIwNTg4MykiCiAgICAgICB4MT0iNTAuMTIwNzgxIgogICAgICAgeTE9IjI0LjM3OTMwOSIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQwIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsMTIuNTM2ODE2LDYuMjA1ODgzKSIKICAgICAgIHgxPSI0Mi43NTgwNzYiCiAgICAgICB5MT0iMjMuNTI2NjQ0IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNDEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsNi4yMDU4ODMpIgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQzIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDUxLjQ2MzE4LDYuMjA1ODgzKSIKICAgICAgIHgxPSI1MC4xMjA3ODEiCiAgICAgICB5MT0iMjQuMzc5MzA5IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0NSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjMwIgogICAgICAgeTE9IjYiCiAgICAgICB4Mj0iMzQiCiAgICAgICB5Mj0iNTciIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtNi00LTEiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQ2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0wLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDUxLjQ2MzE4LDYuMjA1ODgzKSIKICAgICAgIHgxPSI1MC4xMjA3ODEiCiAgICAgICB5MT0iMjQuMzc5MzA5IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4OTUtNi00LTEiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzI5ZmNmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4OTctNy0wLTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS01LTktNCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4OTUtOC0wIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0NCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjgyNzI2NTI2LDAsMCwwLjg1Mjk0MTIxLDEyLjUzNjgxNiw2LjIwNTg4MykiCiAgICAgICB4MT0iNDIuNzU4MDc2IgogICAgICAgeTE9IjIzLjUyNjY0NCIKICAgICAgIHgyPSI0NS42MTUyNDYiCiAgICAgICB5Mj0iMzkuNTE0MTAzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODk1LTgtMCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzg5Ny0yLTkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODc7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg5OS00LTQiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODk1LTgtMCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwOTgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44MjcyNjUyNiwwLDAsMC44NTI5NDEyMSwxMi41MzY4MTYsNi4yMDU4ODMpIgogICAgICAgeDE9IjQyLjc1ODA3NiIKICAgICAgIHkxPSIyMy41MjY2NDQiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQtMSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxMDAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTAyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iMzAiCiAgICAgICB5MT0iNiIKICAgICAgIHgyPSIzNCIKICAgICAgIHkyPSI1NyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS02LTQtMSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMxMTAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsNTEuNDYzMTgsNi4yMDU4ODMpIgogICAgICAgeDE9IjUwLjEyMDc4MSIKICAgICAgIHkxPSIyNC4zNzkzMDkiCiAgICAgICB4Mj0iNDUuNjE1MjQ2IgogICAgICAgeTI9IjM5LjUxNDEwMyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg5NS04LTAiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTEyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuODI3MjY1MjYsMCwwLDAuODUyOTQxMjEsMTIuNTM2ODE2LDYuMjA1ODgzKSIKICAgICAgIHgxPSI0Mi43NTgwNzYiCiAgICAgICB5MT0iMjMuNTI2NjQ0IgogICAgICAgeDI9IjQ1LjYxNTI0NiIKICAgICAgIHkyPSIzOS41MTQxMDMiIC8+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI5LjY4NzUiCiAgICAgaW5rc2NhcGU6Y3g9Ii0zLjQwNjQ1MTgiCiAgICAgaW5rc2NhcGU6Y3k9IjMyIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIKICAgICBzaG93Z3JpZD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMjU2MCIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMzYxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOSIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTkiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1nbG9iYWw9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBzaG93Z3VpZGVzPSJ0cnVlIgogICAgIGlua3NjYXBlOmd1aWRlLWJib3g9InRydWUiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMzA0NiIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDMwNDgiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiCiAgICAgICBzcGFjaW5neD0iMTYiCiAgICAgICBzcGFjaW5neT0iMTYiCiAgICAgICBvcmlnaW54PSIwIgogICAgICAgb3JpZ2lueT0iMCIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8ZwogICAgICAgaWQ9ImczMDE1IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMC43MjksMCwxOS41NzIpIj4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMDg3IgogICAgICAgICBkPSJNIDMyLDU2IDMyLDgiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwYjE1MjE7c3Ryb2tlLXdpZHRoOjg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIGlkPSJwYXRoMzA4Ny02IgogICAgICAgICBkPSJNIDMyLDU2IDMyLDgiCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOnVybCgjbGluZWFyR3JhZGllbnQzMTAyKTtzdHJva2Utd2lkdGg6NDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzMDg3LTYtMiIKICAgICAgICAgZD0iTSAzMSw1NiAzMSw4IgogICAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgPC9nPgogICAgPGcKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0xLjA2MTIwOCwwLDAsMS4wNjEyMDgsMTA2LjI4NDU2LDE0LjE4NDQzMikiCiAgICAgICBpZD0iZzMwMTEiPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoMzM0MyIKICAgICAgICAgZD0ibSA0OSwxOSAwLDggLTgsMCAwLDEwIDgsMCAwLDggMTIsLTEzIHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMTEyKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoMzM0My0yIgogICAgICAgICBkPSJNIDUxLjA0MDc0OCwyNC40ODcwMjEgNTEsMjkgbCAtOCwwIDAsNiA4LDAgMC4wMTcwNSw1LjEzMDY4MiA3LjI2NDE5MSwtOC4xMDY1NzYgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPC9nPgogICAgPGcKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KC0xLjA2MTIwOCwwLDAsMS4wNjEyMDgsMjUuNjMyNzUyLDE0LjE4NDQzMikiCiAgICAgICBpZD0iZzMwMDciPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNC4xNjgzODk4IgogICAgICAgICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL3lvcmlrL0RvY3VtZW50cy9MYWIvRHJhZnQvaWNvbnMvY2hhbmdlcHJvcC5wbmciCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoMzM0My0zIgogICAgICAgICBkPSJtIDE1LDE5IDAsOCA4LDAgMCwxMCAtOCwwIDAsOCBMIDMsMzIgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMxMTApO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojMGIxNTIxO3N0cm9rZS13aWR0aDoxLjk5OTk5OTg4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC14ZHBpPSI0LjE2ODM4OTgiCiAgICAgICAgIGlua3NjYXBlOmV4cG9ydC1maWxlbmFtZT0iL2hvbWUveW9yaWsvRG9jdW1lbnRzL0xhYi9EcmFmdC9pY29ucy9jaGFuZ2Vwcm9wLnBuZyIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjYyIKICAgICAgICAgaWQ9InBhdGgzMzQzLTItNSIKICAgICAgICAgZD0iTSAxMi45NTkyNTIsMjQuNDg3MDIxIDEzLDI5IGwgOCwwIDAsNiAtOCwwIC0wLjAxNzA1LDUuMTMwNjgyIC03LjI2NDE5MSwtOC4xMDY1NzYgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPC9nPgogICAgPHRleHQKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICBzdHlsZT0iZm9udC1zaXplOjMyLjI3MDQ5NjM3cHg7Zm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDtsaW5lLWhlaWdodDo3Ni45OTk5OTgwOSU7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3BhY2luZzowcHg7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MS4yMDQzOTgxNjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO2ZvbnQtZmFtaWx5OlNhbnM7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpTYW5zIEJvbGQiCiAgICAgICB4PSI0MS4yODQ0NjYiCiAgICAgICB5PSIyNS43MDIwNzYiCiAgICAgICBpZD0idGV4dDQ0OTktMSIKICAgICAgIHNvZGlwb2RpOmxpbmVzcGFjaW5nPSI3Ni45OTk5OTglIj48dHNwYW4KICAgICAgICAgc29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgaWQ9InRzcGFuNDQ5Ny03IgogICAgICAgICB4PSI0MS4yODQ0NjYiCiAgICAgICAgIHk9IjI1LjcwMjA3NiIKICAgICAgICAgc3R5bGU9ImZvbnQtc2l6ZTozMi4yNzA0OTYzN3B4O2ZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO3RleHQtYWxpZ246c3RhcnQ7bGluZS1oZWlnaHQ6NzYuOTk5OTk4MDklO3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOiMwMDAwZmY7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuMjA0Mzk4MTY7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtmb250LWZhbWlseTpTYW5zOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246U2FucyBCb2xkIj5aPC90c3Bhbj48L3RleHQ+CiAgPC9nPgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTU3ODEiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgICAgPGNjOmxpY2Vuc2UKICAgICAgICAgICByZGY6cmVzb3VyY2U9IiIgLz4KICAgICAgICA8ZGM6ZGF0ZT5Nb24gT2N0IDEwIDEzOjQ0OjUyIDIwMTEgKzAwMDA8L2RjOmRhdGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9EcmFmdC9SZXNvdXJjZXMvaWNvbnMvRHJhZnRfVHJpbWV4LnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bYWdyeXNvbl0gQWxleGFuZGVyIEdyeXNvbjwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y29udHJpYnV0b3I+CiAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICA8cmRmOkJhZz4KICAgICAgICAgICAgPHJkZjpsaT5hcnJvdzwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmFycm93czwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmxpbmU8L3JkZjpsaT4KICAgICAgICAgIDwvcmRmOkJhZz4KICAgICAgICA8L2RjOnN1YmplY3Q+CiAgICAgICAgPGRjOmRlc2NyaXB0aW9uPkEgdmVydGljYWwgbGluZSB3aXRoIGFuIGFycm93IHBvaW50aW5nIGF3YXkgZnJvbSBpdCBvbiBlYWNoIHNpZGU8L2RjOmRlc2NyaXB0aW9uPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KPC9zdmc+Cg==
"""
-help_b64=\
-"""
+help_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0IgogICBoZWlnaHQ9IjY0IgogICBpZD0ic3ZnNjM2MSIKICAgc29kaXBvZGk6dmVyc2lvbj0iMC4zMiIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMC40OC41IHIxMDA0MCIKICAgc29kaXBvZGk6ZG9jbmFtZT0iaGVscC1icm93c2VyLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMSI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyNDMxIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AyNDMzIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYjhiOGI4O3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDI0MzUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyMTY0NCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMjE2NDYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjA7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMjE2NDgiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyMTY0NCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDIxNjUwIgogICAgICAgY3g9IjI1LjEyNSIKICAgICAgIGN5PSIzNi43NSIKICAgICAgIGZ4PSIyNS4xMjUiCiAgICAgICBmeT0iMzYuNzUiCiAgICAgICByPSIxNS43NSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMSwwLDAsMC41OTUyMzgsMCwxNC44NzUpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDI5MzMiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDI5MzUiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzljYmNkZTtzdG9wLW9wYWNpdHk6MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyOTM3IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMyMDRhODciIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyOTMzIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MjIwNyIKICAgICAgIGN4PSIyNi41NDQzMjEiCiAgICAgICBjeT0iMjguNDU4NzI1IgogICAgICAgZng9IjI2LjU0NDMyMSIKICAgICAgIGZ5PSIyOC40NTg3MjUiCiAgICAgICByPSIyMi4zNzYxMTYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4yMzgzNDIsMC4wMDU5NTQ4NSwtMC4wMDY1MDc3NiwxLjM1MTI3MiwtNi45OTI1MTMsLTkuNzQ0ODQyKSIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MjQzMSIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDI0MzciCiAgICAgICBjeD0iLTE5LjUxNTYzOCIKICAgICAgIGN5PSIxNi44NTU2NjMiCiAgICAgICBmeD0iLTE5LjUxNTYzOCIKICAgICAgIGZ5PSIxNi44NTU2NjMiCiAgICAgICByPSI4Ljc1MzY0MyIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoNC40NDU5OTEsMCwwLDYuODY2NSw2Ny4yNTA3MSwtMTA0LjY2NzkpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM3ODAiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzg2IgogICAgICAgeDE9IjQxLjY0Mjg1NyIKICAgICAgIHkxPSI1OC43ODU3MTMiCiAgICAgICB4Mj0iMjIuMzU3MTQzIgogICAgICAgeTI9IjcuMzU3MTQyOSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzgwIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM0NjVhNDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM3ODIiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM3MjlmY2Y7c3RvcC1vcGFjaXR5OjA7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzc4NCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpbmtzY2FwZTpndWlkZS1iYm94PSJ0cnVlIgogICAgIHNob3dndWlkZXM9InRydWUiCiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjUuNjU2ODU0MiIKICAgICBpbmtzY2FwZTpjeD0iOTIuMDU4NTM5IgogICAgIGlua3NjYXBlOmN5PSI0OC4yNzgzNDQiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNjAwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjgzNyIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iMjciCiAgICAgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9InRydWUiCiAgICAgZmlsbD0iI2RlYjg4NyIKICAgICBzdHJva2U9IiMyMDRhODciCiAgICAgYm9yZGVybGF5ZXI9InRydWUiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgaWQ9IkdyaWRGcm9tUHJlMDQ2U2V0dGluZ3MiCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBvcmlnaW54PSIwcHgiCiAgICAgICBvcmlnaW55PSIwcHgiCiAgICAgICBzcGFjaW5neD0iMXB4IgogICAgICAgc3BhY2luZ3k9IjFweCIKICAgICAgIGNvbG9yPSIjNzE3MWNkIgogICAgICAgZW1wY29sb3I9IiM3YjdiYzMiCiAgICAgICBvcGFjaXR5PSIwLjEyMTU2ODYzIgogICAgICAgZW1wb3BhY2l0eT0iMC41MzcyNTQ5IgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTQiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPkhlbHAgQnJvd3NlcjwvZGM6dGl0bGU+CiAgICAgICAgPGRjOmRhdGU+MjAwNS0xMS0wNjwvZGM6ZGF0ZT4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlR1b21hcyBLdW9zbWFuZW48L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICA8cmRmOkJhZz4KICAgICAgICAgICAgPHJkZjpsaT5oZWxwPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+YnJvd3NlcjwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmRvY3VtZW50YXRpb248L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5kb2NzPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+bWFuPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+aW5mbzwvcmRmOmxpPgogICAgICAgICAgPC9yZGY6QmFnPgogICAgICAgIDwvZGM6c3ViamVjdD4KICAgICAgICA8Y2M6bGljZW5zZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktc2EvMi4wLyIgLz4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5KYWt1YiBTdGVpbmVyLCBBbmRyZWFzIE5pbHNzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICAgIDxkYzpzb3VyY2U+aHR0cDovL3RpZ2VydC5jb208L2RjOnNvdXJjZT4KICAgICAgPC9jYzpXb3JrPgogICAgICA8Y2M6TGljZW5zZQogICAgICAgICByZGY6YWJvdXQ9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LXNhLzIuMC8iPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9SZXByb2R1Y3Rpb24iIC8+CiAgICAgICAgPGNjOnBlcm1pdHMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly93ZWIucmVzb3VyY2Uub3JnL2NjL0Rpc3RyaWJ1dGlvbiIgLz4KICAgICAgICA8Y2M6cmVxdWlyZXMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly93ZWIucmVzb3VyY2Uub3JnL2NjL05vdGljZSIgLz4KICAgICAgICA8Y2M6cmVxdWlyZXMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly93ZWIucmVzb3VyY2Uub3JnL2NjL0F0dHJpYnV0aW9uIiAvPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9EZXJpdmF0aXZlV29ya3MiIC8+CiAgICAgICAgPGNjOnJlcXVpcmVzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9TaGFyZUFsaWtlIiAvPgogICAgICA8L2NjOkxpY2Vuc2U+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIKICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwLDE2KSI+CiAgICA8cGF0aAogICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgc3R5bGU9ImZpbGw6IzcyOWZjZjtzdHJva2U6IzBiMTUyMTtzdHJva2Utd2lkdGg6Mi4wNjg5NjU0NDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBpZD0icGF0aDI5OTIiCiAgICAgICBzb2RpcG9kaTpjeD0iMzIiCiAgICAgICBzb2RpcG9kaTpjeT0iMzIiCiAgICAgICBzb2RpcG9kaTpyeD0iMzAiCiAgICAgICBzb2RpcG9kaTpyeT0iMzAiCiAgICAgICBkPSJNIDYyLDMyIEEgMzAsMzAgMCAxIDEgMiwzMiAzMCwzMCAwIDEgMSA2MiwzMiB6IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC45NjY2NjY2NywwLDAsMC45NjY2NjY2NywxLjA2NjY2NjYsLTE0LjkzMzMzMykiIC8+CiAgICA8cGF0aAogICAgICAgc29kaXBvZGk6dHlwZT0iYXJjIgogICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM3ODYpO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojNzI5ZmNmO3N0cm9rZS13aWR0aDoyLjIyMjIyMjMzO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgIGlkPSJwYXRoMjk5Mi0zIgogICAgICAgc29kaXBvZGk6Y3g9IjMyIgogICAgICAgc29kaXBvZGk6Y3k9IjMyIgogICAgICAgc29kaXBvZGk6cng9IjMwIgogICAgICAgc29kaXBvZGk6cnk9IjMwIgogICAgICAgZD0iTSA2MiwzMiBBIDMwLDMwIDAgMSAxIDIsMzIgMzAsMzAgMCAxIDEgNjIsMzIgeiIKICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDAuOSwwLDAsMC45LDMuMTk5OTk5NiwtMTIuOCkiIC8+CiAgICA8cGF0aAogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS42ODU3NzYyLDAsMCwxLjY1NjYzODQsNjYuNTUzNzY0LC0xNC4zNTU3OSkiCiAgICAgICBzdHlsZT0iZm9udC1zaXplOjM0LjE1MzIyODc2cHg7Zm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7dGV4dC1hbGlnbjpzdGFydDtsaW5lLWhlaWdodDoxMjUlO3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOnVybCgjcmFkaWFsR3JhZGllbnQyNDM3KTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzcyOWZjZjtzdHJva2Utd2lkdGg6MS4xOTY3ODUwOTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxO2ZvbnQtZmFtaWx5OkJpdHN0cmVhbSBWZXJhIFNhbnMiCiAgICAgICBkPSJtIC0yMC4yNSw1LjY2MTU4MzggYyAtMS4wNTkwMTksMi42M2UtNSAtMi4xNDc2MzcsMC4xMjMyMzU2IC0zLjI4MTI1LDAuMzQzNzUgLTEuMTMyOTI1LDAuMjIwNDI4MyAtMi4wMDk0MTMsMC41Mzc1MTI1IC0zLjM3OTI1MSwxIC0wLjAxMDM3LC0wLjAwMTIxIC0wLjAyMDg4LC0wLjAwMTIxIC0wLjAzMTI1LDAgLTAuMDEyMDQsMC4wMDg2MSAtMC4wMjI2NCwwLjAxOTIxNCAtMC4wMzEyNSwwLjAzMTI1IC0wLjAxMjA0LDAuMDA4NjEgLTAuMDIyNjQsMC4wMTkyMTQgLTAuMDMxMjUsMC4wMzEyNSAtMC4wMDEyLDAuMDEwMzcgLTAuMDAxMiwwLjAyMDg4IDAsMC4wMzEyNSAtMC4wMDEyLDAuMDEwMzcgLTAuMDAxMiwwLjAyMDg4IDAsMC4wMzEyNSBsIDAsNS4xNTYyNTAyIGMgLTAuMDAxMiwwLjAxMDM3IC0wLjAwMTIsMC4wMjA4OCAwLDAuMDMxMjUgLTAuMDAxMiwwLjAxMDM3IC0wLjAwMTIsMC4wMjA4OCAwLDAuMDMxMjUgMC4wMDg2LDAuMDEyMDQgMC4wMTkyMSwwLjAyMjY0IDAuMDMxMjUsMC4wMzEyNSAwLjAwODYsMC4wMTIwNCAwLjAxOTIxLDAuMDIyNjQgMC4wMzEyNSwwLjAzMTI1IDAuMDEwMzcsMC4wMDEyIDAuMDIwODgsMC4wMDEyIDAuMDMxMjUsMCAwLjAxMDM3LDAuMDAxMiAwLjAyMDg4LDAuMDAxMiAwLjAzMTI1LDAgMC4wMTAzNywwLjAwMTIgMC4wMjA4OCwwLjAwMTIgMC4wMzEyNSwwIDAuMDEwMzcsMC4wMDEyIDAuMDIwODgsMC4wMDEyIDAuMDMxMjUsMCAxLjE0MjQzOCwtMC43MTkwNDMgMS44NjI2MDMsLTEuMjY3MTM4IDIuOTEwNTAxLC0xLjYyNSAxLjA0ODE0MSwtMC4zNjg3NTYgMi4wNDMxMTYsLTAuNTYyNDc5IDIuOTM3NSwtMC41NjI1IDAuOTQ5MjE4LDIuMWUtNSAxLjY0NDkyNSwwLjIxMDU0NSAyLjE1NjI1LDAuNjI1IDAuNTA4NzIzLDAuNDAyMDkgMC43ODEyMzgsMC45ODMwNCAwLjc4MTI1LDEuNzE4NzUgLTEwZS02LDAuNDgwNjU3IC0wLjE0NDE4OCwwLjk1MTQxIC0wLjQzNzUsMS40Mzc1IC0wLjI4Mjk5MSwwLjQ4NzAxNiAtMC43NDAyNjUsMS4yNDM5MTEgLTEuMzc1LDEuODA3MTY2IEwgLTIwLjkzNzUsMTYuNzUgYyAtMS4yMDE0NTksMS4wODA0OSAtMS43Nzk1MTYsMS45OTEwMjIgLTIuMTY1MjczLDIuNzE4NzUgLTAuMzgzMTEzLDAuNzExNDQ2IC0wLjM1OTc2OSwxLjIzMTY1NiAtMC4zNTk3NjksMi4xNDk4MzIgbCAwLDAuODEyNSBjIC0wLjAwMTIsMC4wMTAzNyAtMC4wMDEyLDAuMDIwODggMCwwLjAzMTI1IC0wLjAwMTIsMC4wMTAzNyAtMC4wMDEyLDAuMDIwODggMCwwLjAzMTI1IDAuMDA4NiwwLjAxMjA0IDAuMDE5MjEsMC4wMjI2NCAwLjAzMTI1LDAuMDMxMjUgMC4wMDg2LDAuMDEyMDQgMC4wMTkyMSwwLjAyMjY0IDAuMDMxMjUsMC4wMzEyNSAwLjAxMDM3LDAuMDAxMiAwLjAyMDg4LDAuMDAxMiAwLjAzMTI1LDAgMC4wMTAzNywwLjAwMTIgMC4wMjA4OCwwLjAwMTIgMC4wMzEyNSwwIGwgNS42ODEyOTIsLTAuMDI4MyBjIDAuMDEwMzcsMC4wMDEyIDAuMDIwODgsMC4wMDEyIDAuMDMxMjUsMCAwLjAxMDM3LDAuMDAxMiAwLjAyMDg4LDAuMDAxMiAwLjAzMTI1LDAgMC4wMTIwNCwtMC4wMDg2IDAuMDIyNjQsLTAuMDE5MjEgMC4wMzEyNSwtMC4wMzEyNSAwLjAxMjA0LC0wLjAwODYgMC4wMjI2NCwtMC4wMTkyMSAwLjAzMTI1LC0wLjAzMTI1IDAuMDAxMiwtMC4wMTAzNyAwLjAwMTIsLTAuMDIwODggMCwtMC4wMzEyNSAwLjAwMTIsLTAuMDEwMzcgMC4wMDEyLC0wLjAyMDg4IDAsLTAuMDMxMjUgbCAwLC0wLjc1IGMgLTEuMWUtNSwtMC40NjgxOTYgMC4xNDgzNywtMC41NzY4ODUgMC4zNzUsLTAuOTY1Mjg2IDAuMjIyMjk1LC0wLjM5MTI4NCAwLjcwODA3MywtMC45NTAzNTkgMS40Njg3NSwtMS42MjUgbCAxLjA2MjUsLTAuOTM3NSBjIDEuMDY2NTg4LC0wLjk4MjMxIDEuODMwNjU5LC0xLjg4NDY1NCAyLjI4MTI1LC0yLjc1IDAuNDQ5MjY5LC0wLjg3NDA0NiAwLjY4NzQ4MiwtMi4wODY4MzYgMC42ODc1LC0zLjE4MjE2NiAtMS44ZS01LC0yLjEyNjI2NSAtMC43NDM3NjksLTMuNzM0MDI3OCAtMi4yMTg3NSwtNC44NDM3NTAyIC0xLjQ3NTE5NywtMS4xMjEwMjUyIC0zLjYwNjI0LC0xLjY4NzQ3MzcgLTYuMzc1LC0xLjY4NzQ5NiB6IgogICAgICAgaWQ9InBhdGgxNTU0IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY3NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7c3Ryb2tlOiM3MjlmY2Y7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gMjcsMjcgMTAsMCAwLDEwIC0xMCwwIHoiCiAgICAgICBpZD0icGF0aDM3ODgiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogIDwvZz4KPC9zdmc+Cg==
"""
-edit_b64=\
-"""
+edit_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjkwLjAwMDAwMCIKICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjkwLjAwMDAwMCIKICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS9qaW1tYWMvRGVza3RvcC93aS1maS5wbmciCiAgIHdpZHRoPSI1MS4yMDAwMDEiCiAgIGhlaWdodD0iNTEuMjAwMDAxIgogICBpZD0ic3ZnMTEzMDAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMCByMTUyOTkiCiAgIHNvZGlwb2RpOmRvY25hbWU9IlByZWZlcmVuY2VzLWdlbmVyYWwuc3ZnIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMzIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MjI1MCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMjI1MiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AyMjU0IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MjI2NSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMjI2NyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AyMjY5IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MjI1NyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMjI1OSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AyMjYxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA4NyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMzNDY1YTQ7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzA4OSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMDk1IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM5ZmJjZTE7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNmI5NWNhO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDIyNDIiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMjI0NCIKICAgICAgICAgb2Zmc2V0PSIwLjc1IgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojM2Q2YWE1O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM4NmViNDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMDkxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA3NyI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM5OGEwYTk7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzA3OSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2MzZDBkZDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMDgxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA2MSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzA2MyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzAwMDAwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzMDY1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0OSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNiNmI2YjY7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzA1MSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyMjYyIgogICAgICAgICBvZmZzZXQ9IjAuNSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2YyZjJmMjtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmYWZhZmE7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjAuNjc2MTI5NTgiCiAgICAgICAgIGlkPSJzdG9wMjI2NCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AyMjY4IgogICAgICAgICBvZmZzZXQ9IjAuODQwNTE3MjIiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNkOGQ4ZDg7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDIyNjYiCiAgICAgICAgIG9mZnNldD0iMC44NzUiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmMmYyZjI7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZGJkYmRiO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDMwNTMiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMDQ5IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA1NSIKICAgICAgIHgxPSIxOS42NDgzNDIiCiAgICAgICB5MT0iNDIuMjUzNjAxIgogICAgICAgeDI9IjIwLjYzMTIyNCIKICAgICAgIHkyPSI2Ljc3NTgwMzEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45MzY4MjEzMywwLDAsMC45MzY4MjEzMywyLjcwNjEyMDUsMS4yOTg4NTk3KSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzA2MSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNjciCiAgICAgICB4MT0iNTAuMTUyOTMxIgogICAgICAgeTE9Ii0zLjYzMjQ0NzciCiAgICAgICB4Mj0iMjUuMjkxMDg2IgogICAgICAgeTI9Ii00LjMwMDI2NTMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45MzY4MjEzMywwLDAsMC45MzY4MjEzMywyLjgxODg4NjUsLTEuMDMxNDkzMikiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMwNzciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDgzIgogICAgICAgeDE9IjM4LjIyNzY1NCIKICAgICAgIHkxPSIxMy42MDI1MjciCiAgICAgICB4Mj0iMzcuNTM1MzciCiAgICAgICB5Mj0iNi42Mjg1ODk2IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTM2ODIxMzMsMCwwLDAuOTM2ODIxMzMsMy4wMzczMzY1LDEuOTYxMjkyOCkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMwODciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDkzIgogICAgICAgeDE9IjkuNzUwMzI0MiIKICAgICAgIHkxPSIzMi4yODM3NiIKICAgICAgIHgyPSIxNi45MTUyOTciCiAgICAgICB5Mj0iMzkuNDQzMjE4IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTM2ODIxMzMsMCwwLDAuOTM2ODIxMzMsMi43MDYxMjA1LDEuMjk4ODU5NykiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDIyNTciCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyMjYzIgogICAgICAgeDE9IjEyLjAwNDY5NyIKICAgICAgIHkxPSIzNS42ODg0NjEiCiAgICAgICB4Mj0iMTAuNjUwODA1IgogICAgICAgeTI9IjMzLjE5NDk2NSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjA3NDQwNDMsLTAuMDI4MTIyOTQsMC4wMjgxMjI5NCwxLjA3NDQwNDMsMS42OTk2Mzg0LC0zLjkxNTUyOTYpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyMjY1IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MjI3MSIKICAgICAgIHgxPSIxNC4wMTc1NDIiCiAgICAgICB5MT0iMzYuOTQyNTQzIgogICAgICAgeDI9IjE1LjQxNTc5MyIKICAgICAgIHkyPSIzOC4yNjgzNjgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45MzY2Mzg5MywtMC4wMTg0Nzg2MSwwLjAxODQ3ODYxLDAuOTM2NjM4OTMsMi4zMDc5MzI4LDAuMzM5MDkyMykiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDIyNTAiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyMjU2IgogICAgICAgeDE9IjMxLjE3NzQwNCIKICAgICAgIHkxPSIxOS44MjE1MTQiCiAgICAgICB4Mj0iNDAuODU5MTc3IgogICAgICAgeTI9IjkuNjU2ODUzNyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjA2NjY2NjcsMCwwLDEuMDY2NjY2NywwLC00KSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MjI1MCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDIyNjMtNSIKICAgICAgIHgxPSIxMi4wMDQ2OTciCiAgICAgICB5MT0iMzUuNjg4NDYxIgogICAgICAgeDI9IjEwLjY1MDgwNSIKICAgICAgIHkyPSIzMy4xOTQ5NjUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS4wNzQ0MDQzLC0wLjAyODEyMjk0LDAuMDI4MTIyOTQsMS4wNzQ0MDQzLC05OS41MjQ4MTQsLTU0Ljg0MjM0OSkiIC8+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBzdHJva2U9IiMyMDRhODciCiAgICAgZmlsbD0iIzM0NjVhNCIKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMC4yNTQ5MDE5NiIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6em9vbT0iMTIuMTA5Mzc1IgogICAgIGlua3NjYXBlOmN4PSIyNS42IgogICAgIGlua3NjYXBlOmN5PSIyNS42IgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIKICAgICBzaG93Z3JpZD0iZmFsc2UiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpzaG93cGFnZXNoYWRvdz0iZmFsc2UiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxNTM2IgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjgwMSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiIC8+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhNCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkpha3ViIFN0ZWluZXI8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnNvdXJjZT5odHRwOi8vamltbWFjLm11c2ljaGFsbC5jejwvZGM6c291cmNlPgogICAgICAgIDxjYzpsaWNlbnNlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS8yLjAvIiAvPgogICAgICAgIDxkYzp0aXRsZT5QcmVmZXJlbmNlcyBTeXN0ZW08L2RjOnRpdGxlPgogICAgICAgIDxkYzpzdWJqZWN0PgogICAgICAgICAgPHJkZjpCYWc+CiAgICAgICAgICAgIDxyZGY6bGk+cHJlZmVyZW5jZXM8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5zZXR0aW5nczwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmNvbnRyb2wgcGFuZWw8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT50d2Vha3M8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5zeXN0ZW08L3JkZjpsaT4KICAgICAgICAgIDwvcmRmOkJhZz4KICAgICAgICA8L2RjOnN1YmplY3Q+CiAgICAgIDwvY2M6V29yaz4KICAgICAgPGNjOkxpY2Vuc2UKICAgICAgICAgcmRmOmFib3V0PSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS8yLjAvIj4KICAgICAgICA8Y2M6cGVybWl0cwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvUmVwcm9kdWN0aW9uIiAvPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9EaXN0cmlidXRpb24iIC8+CiAgICAgICAgPGNjOnJlcXVpcmVzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9Ob3RpY2UiIC8+CiAgICAgICAgPGNjOnJlcXVpcmVzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9BdHRyaWJ1dGlvbiIgLz4KICAgICAgICA8Y2M6cGVybWl0cwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvRGVyaXZhdGl2ZVdvcmtzIiAvPgogICAgICAgIDxjYzpyZXF1aXJlcwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvU2hhcmVBbGlrZSIgLz4KICAgICAgPC9jYzpMaWNlbnNlPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO29wYWNpdHk6MTtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMDU1KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6Izg4OGE4NTtzdHJva2Utd2lkdGg6MS4wNjY2NjYzNjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyOm5vbmU7bWFya2VyLXN0YXJ0Om5vbmU7bWFya2VyLW1pZDpub25lO21hcmtlci1lbmQ6bm9uZSIKICAgICAgIGQ9Im0gMTkuMTAwNDk0LDE4LjYzMDA1NCAyMC4yNTg3NjEsMjAuNzI3MTczIGMgMC44MTk3MTksMC45MzY4MjEgMy40MTcwNzgsMS42NjA4NjUgNS4xNTI1MTgsMCAxLjY3NTg2OCwtMS42MDM4NTQgMS4yODgxMjksLTMuODY0Mzg5IC0wLjM1MTMwOCwtNS41MDM4MjYgTCAyNC43MjE0MjIsMTMuMDA5MTI2IEMgMjcuMTIxNDIyLDYuMzQyNDYgMjIuMjYzOTQsMC43NDI5MjA1IDE1Ljk5NzI3NCwxLjk0MjkyMDUgbCAtMS4zNDY2ODIsMS4yMjk1NzgxIDQuMjE1Njk2LDMuOTgxNDkwNCAwLjIzNDIwNiwzLjUxMzA4NCAtMy4xNDc1NjUsMi44NzMxNzcgLTMuNzYxNDkyLC0wLjQxNDAyMSAtMy44NjQzODc4LC0zLjYzMDE4MiBjIDAsMCAtMS4zNTQ3OTYxLDEuMzM4NTY0IC0xLjM1NDc5NjEsMS4zMzg1NjQgLTAuNjMwMTQ3Nyw2LjAxNzQwNSA1LjY2MTU3MzksMTEuMzk1NDQzIDEyLjEyODI0MDksNy43OTU0NDMgeiIKICAgICAgIGlkPSJwYXRoMjE0MCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2N6Y2NjY2NjY2Njc2MiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2N6Y2NjY2NjY2NjY2MiCiAgICAgICBpZD0icGF0aDMwNTciCiAgICAgICBkPSJtIDE5LjMyNTIxMSwxNy4yNjk0NCAyMC40ODMwNzQsMjEuMzYyNzg2IGMgMC42MzQ1NjcsMC43MjUyMTkgMi42NDUyNTUsMS4yODU3MjMgMy45ODg3MDgsMCAxLjI5NzMzNywtMS4yNDE1ODggMC45OTcxNzcsLTIuOTkxNTMxIC0wLjI3MTk1NywtNC4yNjA2NjUgTCAyMy44MDA3MzUsMTMuNDQyMzI5IGMgMS42LC02LjkzMzMzNCAtMS45ODI3MDcsLTEwLjY3MTYxMzggLTcuMzE2MDQxLC0xMC41MzgyODA1IGwgLTAuMjg4MTM5LDAuMjkxNjAyIDMuODQzMTE4LDMuNDUyMDE3NSAwLjEzODg0Myw0LjQ2MDU4MSAtMy44NTQ4NDUsMy41MTgzODEgLTQuNTI1MTI2LC0wLjQ4ODc1NiAtMy4zODgzNTQ1LC0zLjE5MDkxMyAtMC4zNzYxNDYyLDAuNDU4NzMgQyA3LjcwMDcxMDksMTcuNzcyMzU3IDE0Ljk1ODU0NCwyMC42Njk0NCAxOS4zMjUyMTEsMTcuMjY5NDQgWiIKICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO29wYWNpdHk6MC40MjYxMzYzOTtmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjEuMDY2NjY1Nzc7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlcjpub25lO21hcmtlci1zdGFydDpub25lO21hcmtlci1taWQ6bm9uZTttYXJrZXItZW5kOm5vbmUiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHJlY3QKICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO29wYWNpdHk6MC4xNzA0NTQ1NjtmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOnVybCgjbGluZWFyR3JhZGllbnQzMDY3KTtzdHJva2Utd2lkdGg6MS4wNjY2NjM2MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyOm5vbmU7bWFya2VyLXN0YXJ0Om5vbmU7bWFya2VyLW1pZDpub25lO21hcmtlci1lbmQ6bm9uZSIKICAgICAgIGlkPSJyZWN0MzA1OSIKICAgICAgIHdpZHRoPSIyNC44MTk0OTQiCiAgICAgICBoZWlnaHQ9IjIuMTkyNTI0IgogICAgICAgeD0iMjcuMTk5NzI2IgogICAgICAgeT0iLTUuNTg0NzY1IgogICAgICAgcng9IjAuOTQyODA2MTIiCiAgICAgICByeT0iMC45NDI4MDYxMiIKICAgICAgIHRyYW5zZm9ybT0icm90YXRlKDQ1LjczODE5KSIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtvcGFjaXR5OjE7ZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzA4Myk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOiM4NzhmOWQ7c3Ryb2tlLXdpZHRoOjEuMDY2NjY2MzY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlcjpub25lO21hcmtlci1zdGFydDpub25lO21hcmtlci1taWQ6bm9uZTttYXJrZXItZW5kOm5vbmUiCiAgICAgICBkPSJNIDIzLjk5ODcxNCwyOC4xMzM3MzkgQyAyNC44ODc4MjQsMjcuMzcxNjQ1IDM4LjE2ODEzNywxMy43ODg2NjIgMzguMTY4MTM3LDEzLjc4ODY2MiBMIDQxLjQ0NzAxMSwxMy41NTQ0NTcgNDYuNTk5NTI5LDYuNDExMTkgNDIuMzA2OTEzLDIuNTg2OTg1MyAzNS42MzIwNjEsOC4zMjUwMTkgdiAzLjI3ODg3NSBsIC0xMy41ODM5MSwxNC4xMTA4NzIgYyAtMC42NDQwNjQsMC42NDQwNjQgMS4xMzA4NDQsMy4xMjE1ODggMS45NTA1NjMsMi40MTg5NzMgeiIKICAgICAgIGlkPSJwYXRoMjE0NCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjYyIKICAgICAgIGlkPSJwYXRoMzA4NSIKICAgICAgIGQ9Ik0gMjMuODk1NDUzLDI3LjAyNDQ4NSBDIDI0LjU4NTM0NCwyNi40MzMxNSAzNy43ODgxNDcsMTIuOTEyNjkxIDM3Ljc4ODE0NywxMi45MTI2OTEgTCA0MC45MTE5NjksMTIuNjQ4MTU5IDQ1LjQwNjgxMyw2LjYwODYyMyA0Mi4zMjQ0MzMsMy44ODk3MDA5IDM2LjQ4Mjc1LDguOTIxNjcxIDM2LjY0ODM1OCwxMS45NjI2OSAyMy4xMjcxOCwyNi4xNDExNjggYyAtMC40OTk3NTMsMC40OTk3NTMgMC4xMzIyMjUsMS40Mjg1MDEgMC43NjgyNzMsMC44ODMzMTcgeiIKICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO29wYWNpdHk6MC41Mzk3NzI3MjtmaWxsOm5vbmU7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOnVybCgjbGluZWFyR3JhZGllbnQyMjU2KTtzdHJva2Utd2lkdGg6MS4wNjY2NjY5NjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyOm5vbmU7bWFya2VyLXN0YXJ0Om5vbmU7bWFya2VyLW1pZDpub25lO21hcmtlci1lbmQ6bm9uZSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTt2aXNpYmlsaXR5OnZpc2libGU7ZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzA5Myk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOiMyMDRhODc7c3Ryb2tlLXdpZHRoOjEuMDY2NjY2MzY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaG9mZnNldDowO3N0cm9rZS1vcGFjaXR5OjE7bWFya2VyOm5vbmU7bWFya2VyLXN0YXJ0Om5vbmU7bWFya2VyLW1pZDpub25lO21hcmtlci1lbmQ6bm9uZSIKICAgICAgIGQ9Im0gOS4wMjk2NjUyLDQyLjUxODk5OCBjIDEuNDA0MzU5OCwxLjU2MjkxMSA1LjMwNTI2MzgsMi4yNzAwNDMgNy4wMzUxMzk4LC0wLjc1NzI0MSAwLjc1NDI0OCwtMS4zMTk5MzIgMi4yMzM1NCwtNS4wMTYzMjIgOC44MzMyMDQsLTEwLjk1NjAxOSAxLjEwODQyMiwtMC45OTY0NDkgMi4yODI1NjksLTMuMjc1ODgxIDEuMjg3MTk2LC00LjUwNTQ1OSBMIDIzLjYwODk0NiwyMy43MjQwMiBjIC0xLjA1MzkyMywtMS4xNzEwMjYgLTMuOTgzMzc1LC0wLjYyNDc5OSAtNS4xODUyNTMsMS4wMTQyNjggLTMuNTgyNjc0LDQuOTAyNjA3IC05LjQzNTgxMTEsOC44MDUyMDUgLTEwLjc1NTc0MzksOS4yNzY2MSAtMi41MjU3ODA4LDAuOTAyMDY0IC0yLjI0MTUwNDYsNC42MjUyMjYgLTAuNTcwNDc4LDYuMzk2MjUzIHoiCiAgICAgICBpZD0icGF0aDIxNDIiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY3NjYyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8Y2lyY2xlCiAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtvcGFjaXR5OjE7ZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTojYTFhMWExO3N0cm9rZS13aWR0aDoxLjA2NjY2NjM2O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXI6bm9uZTttYXJrZXItc3RhcnQ6bm9uZTttYXJrZXItbWlkOm5vbmU7bWFya2VyLWVuZDpub25lIgogICAgICAgaWQ9InBhdGgyMTQ2IgogICAgICAgY3g9IjQxLjgxODQxMyIKICAgICAgIGN5PSIzNi41NDY3NjEiCiAgICAgICByPSIxLjI4ODEyOTMiIC8+CiAgICA8Y2lyY2xlCiAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtvcGFjaXR5OjAuNjAyMjcyNzI7ZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjYwODkzNDQ7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlcjpub25lO21hcmtlci1zdGFydDpub25lO21hcmtlci1taWQ6bm9uZTttYXJrZXItZW5kOm5vbmUiCiAgICAgICBpZD0icGF0aDMxMDEiCiAgICAgICBjeD0iMjEuMzM3MDUzIgogICAgICAgY3k9IjI1LjE3Mzc0OCIKICAgICAgIHI9IjEuMDc2NDU0MiIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtvcGFjaXR5OjE7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTp1cmwoI2xpbmVhckdyYWRpZW50MjI2Myk7c3Ryb2tlLXdpZHRoOjIuNDQ3NDc2Mzk7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXI6bm9uZTttYXJrZXItc3RhcnQ6bm9uZTttYXJrZXItbWlkOm5vbmU7bWFya2VyLWVuZDpub25lIgogICAgICAgZD0ibSAxOS45MjQxNjUsMjcuNTk5Nzk0IGMgMCwwIC03LjY0Nzg4Myw3Ljc4NjI1NCAtMTEuMjMwNTU3Miw5LjEwNjE4NyIKICAgICAgIGlkPSJwYXRoMzEwMyIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY3NjY2Njc2NjIgogICAgICAgaWQ9InBhdGgyMjcwIgogICAgICAgZD0ibSA5LjM5MzA2ODEsNDEuMzE5MTM2IGMgMS41MzczNDk5LDEuODYxOTkxIDQuOTA2MTY4OSwyLjMwNTMxMSA1Ljk2MzkwMzksLTAuMzk1Mjk1IDAuNzI2NzI3LC0xLjg1NTQ3OSAzLjU1NTg2MywtNi4wNDM1MDYgOC43NDQwODksLTEwLjcxMjkxIDAuODcxMzcsLTAuNzgzMzQ0IDEuNzk0NDA5LC0yLjU3NTI4NCAxLjAxMTkxMSwtMy41NDE4OTggbCAtMi4wMjUyODgsLTIuMDI1Mjg4IGMgLTAuODI4NTI2LC0wLjkyMDU4NCAtMy4xMzE0NywtMC40OTExNzYgLTQuMDc2MzA5LDAuNzk3MzUyIC0yLjgxNjQ2NSwzLjg1NDExIC05LjA0ODkwMSw4Ljg5NTUyNCAtMTAuNTU1NDY2Miw5LjM5MjY2NyAtMi4zMzI1ODEsMC43Njk3MTggLTEuODk1NDU4NiwzLjQzNjA1MyAtMC41ODE4MDYxLDQuODI4MzE5IHoiCiAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtvcGFjaXR5OjAuMTk4ODYzNjc7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDoxLjA2NjY2NjEzO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXI6bm9uZTttYXJrZXItc3RhcnQ6bm9uZTttYXJrZXItbWlkOm5vbmU7bWFya2VyLWVuZDpub25lIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO3Zpc2liaWxpdHk6dmlzaWJsZTtvcGFjaXR5OjAuMjc4NDA5MTE7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTp1cmwoI2xpbmVhckdyYWRpZW50MjI3MSk7c3Ryb2tlLXdpZHRoOjIuNDQ3NDc2Mzk7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlcjpub25lO21hcmtlci1zdGFydDpub25lO21hcmtlci1taWQ6bm9uZTttYXJrZXItZW5kOm5vbmUiCiAgICAgICBkPSJtIDIyLjIxMjkwOSwyOS4zNDUwOTIgYyAwLDAgLTcuODEwOTQ3LDcuMDU4NTY2IC05LjUwODAwMywxMS41ODQwNDgiCiAgICAgICBpZD0icGF0aDIyNDciCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxnCiAgICAgICBpZD0iZzQ1OTgiCiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMDUuMDQ4MDYsNTUuMTY1MDcxKSI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiCiAgICAgICAgIGlkPSJwYXRoMzEwMy05IgogICAgICAgICBkPSJtIC04MS4zMDAyODcsLTIzLjMyNzAyNCBjIDAsMCAtNy42NDc4ODMsNy43ODYyNTQgLTExLjIzMDU1Nyw5LjEwNjE4NyIKICAgICAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTt2aXNpYmlsaXR5OnZpc2libGU7b3BhY2l0eToxO2ZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6dXJsKCNsaW5lYXJHcmFkaWVudDIyNjMtNSk7c3Ryb2tlLXdpZHRoOjIuNDQ3NDc2NjM7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7c3Ryb2tlLW9wYWNpdHk6MTttYXJrZXI6bm9uZTttYXJrZXItc3RhcnQ6bm9uZTttYXJrZXItbWlkOm5vbmU7bWFya2VyLWVuZDpub25lIiAvPgogICAgICA8cGF0aAogICAgICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO3N0cm9rZTojMzAyYjAwO3N0cm9rZS13aWR0aDoxLjY3NDcxODg2O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGQ9Im0gLTY0Ljk2MzA0NSwtMjAuNjAzOTQgNC4xODY3OTksMTUuMDcyNDcwMSAtMTQuMjM1MTEzLC01LjAyNDE1NjEgLTEuNjc0NzE0LC0zLjM0OTQzOCA4LjM3MzU5LC04LjM3MzU5NSB6IgogICAgICAgICBpZD0icGF0aDM5NjkiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjIiAvPgogICAgICA8cGF0aAogICAgICAgICBzdHlsZT0ib3BhY2l0eTowLjc7ZmlsbDojZmNlOTRmO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjgzMDAzODY3IgogICAgICAgICBkPSJtIC04MS43MTAyMzUsLTM3LjM1MTEzNCAtMy4zNDk0MzcsMy4zNDk0MzggMTYuNzQ3MTg5LDE2Ljc0NzE5NCBjIDAsLTIuNTEyMDc4IDAuODM3MzYxLC0zLjM0OTQzOCAzLjM0OTQzOCwtMy4zNDk0MzggeiIKICAgICAgICAgaWQ9InBhdGgzODQzIgogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIiAvPgogICAgICA8cGF0aAogICAgICAgICBzdHlsZT0ib3BhY2l0eTowLjc7ZmlsbDojZWRkNDAwO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjgzMDAzODY3IgogICAgICAgICBkPSJtIC04NS4wNTk2NzIsLTM0LjAwMTcwMyAtMy4zNDk0MzgsMy4zNDk0NSAxNi43NDcxODksMTYuNzQ3MTg5IGMgMCwtMi41MTIwNzggMC44MzczNjIsLTMuMzQ5NDM4IDMuMzQ5NDM4LC0zLjM0OTQzOCB6IgogICAgICAgICBpZD0icGF0aDM4NDMtNyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgICAgPHBhdGgKICAgICAgICAgc3R5bGU9Im9wYWNpdHk6MC43O2ZpbGw6I2M0YTAwMDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MC44MzAwMzg2NyIKICAgICAgICAgZD0ibSAtODguNDA5MTEsLTMwLjY1MjI1MyAtMy4zNDk0MzgsMy4zNDk0MzggMTYuNzQ3MTg5LDE2Ljc0NzE4OSBjIDAsLTIuNTEyMDc5IDAuODM3MzYzLC0zLjM0OTQzOCAzLjM0OTQzOCwtMy4zNDk0MzggeiIKICAgICAgICAgaWQ9InBhdGgzODQzLTUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjAuNTtmaWxsOm5vbmU7c3Ryb2tlOiNlZGQ0MDA7c3Ryb2tlLXdpZHRoOjEuNjc0NzE4ODY7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGQ9Im0gLTg5LjI0NjQ2MywtMjkuMTQ1MDEzIDE1LjA3MjQ2NywxNS4wNzI0NzkiCiAgICAgICAgIGlkPSJwYXRoMzg4OCIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgICAgPHBhdGgKICAgICAgICAgc3R5bGU9Im9wYWNpdHk6MC41O2ZpbGw6bm9uZTtzdHJva2U6I2ZjZTk0ZjtzdHJva2Utd2lkdGg6MS42NzQ3MTg4NjtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0ibSAtODUuODk3MDMzLC0zMi40OTQ0NDcgMTUuMDcyNDc0LDE1LjA3MjQ3MyIKICAgICAgICAgaWQ9InBhdGgzODg4LTUiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMzMDJiMDA7c3Ryb2tlLXdpZHRoOjEuNjc0NzE4ODY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0ibSAtODEuNzEwMjM1LC0zNy4zNTExMzIgLTMuMzQ5NDM3LDMuMzQ5NDM4IDE2Ljc0NzE4OSwxNi43NDcxOTIgYyAwLC0yLjUxMjA3OCAwLjgzNzM2MSwtMy4zNDk0MzggMy4zNDk0MzgsLTMuMzQ5NDM4IHoiCiAgICAgICAgIGlkPSJwYXRoMzg0My01LTYiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMzMDJiMDA7c3Ryb2tlLXdpZHRoOjEuNjc0NzE4ODY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0ibSAtODUuMDU5NjcyLC0zNC4wMDE2OTQgLTMuMzQ5NDM4LDMuMzQ5NDQxIDE2Ljc0NzE4OSwxNi43NDcxODkgYyAwLC0yLjUxMjA3OCAwLjgzNzM2MiwtMy4zNDk0MzggMy4zNDk0MzgsLTMuMzQ5NDM4IHoiCiAgICAgICAgIGlkPSJwYXRoMzg0My01LTYtMiIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgICAgPHBhdGgKICAgICAgICAgc3R5bGU9ImZpbGw6IzMwMmIwMDtzdHJva2U6IzMwMmIwMDtzdHJva2Utd2lkdGg6MC44MzczNTk0M3B4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgIGQ9Im0gLTYyLjQ1MDk2OCwtMTMuMDY3NzA1IGMgLTEuNjc0NzE2LDAgLTQuNjY0NTgxLDIuMTA2OTg5IC01LjAyNDE1NCw0LjE4Njc5ODEgbCA2LjY5ODg3NiwzLjM0OTQzNyAtMS42NzQ3MjIsLTYuNjk4ODc1MSB2IDAiCiAgICAgICAgIGlkPSJwYXRoMzk3MSIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgICAgPHBhdGgKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzMwMmIwMDtzdHJva2Utd2lkdGg6MS42NzQ3MTg4NjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBkPSJtIC04OC40MDkxMSwtMzAuNjUyMjUzIC0zLjM0OTQzOCwzLjM0OTQzOCAxNi43NDcxODksMTYuNzQ3MTg5IGMgMCwtMi41MTIwNzkgMC44MzczNjMsLTMuMzQ5NDM4IDMuMzQ5NDM4LC0zLjM0OTQzOCB6IgogICAgICAgICBpZD0icGF0aDM4NDMtNS02LTkiCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K
"""
-#"""
-#PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIGhlaWdodD0iNDgiCiAgIHdpZHRoPSI0OCIKICAgdmVyc2lvbj0iMS4xIgogICBpZD0ic3ZnMTM3IgogICBzb2RpcG9kaTpkb2NuYW1lPSJFZGl0LnN2ZyIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45Mi4wIHIxNTI5OSI+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhMTQxIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZT48L2RjOnRpdGxlPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgb2JqZWN0dG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBndWlkZXRvbGVyYW5jZT0iMTAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlkPSJuYW1lZHZpZXcxMzkiCiAgICAgc2hvd2dyaWQ9ImZhbHNlIgogICAgIGlua3NjYXBlOnpvb209IjQuOTE2NjY2NyIKICAgICBpbmtzY2FwZTpjeD0iMjQiCiAgICAgaW5rc2NhcGU6Y3k9IjI0IgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmcxMzciIC8+CiAgPGRlZnMKICAgICBpZD0iZGVmczc1Ij4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImEiPgogICAgICA8c3RvcAogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1vcGFjaXR5PSIwIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlkPSJ4IgogICAgICAgeGxpbms6aHJlZj0iI2EiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN5PSI0My41IgogICAgICAgY3g9IjQuOTkzIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjAwMzgsMCwwLDEuNCwyNy45ODgsLTE3LjQpIgogICAgICAgcj0iMi41IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpZD0ieSIKICAgICAgIHhsaW5rOmhyZWY9IiNhIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBjeT0iNDMuNSIKICAgICAgIGN4PSI0Ljk5MyIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi4wMDM4LDAsMCwxLjQsLTIwLjAxMiwtMTA0LjQpIgogICAgICAgcj0iMi41IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0icyIKICAgICAgIHkyPSIzOS45OTkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgyPSIyNS4wNTgiCiAgICAgICB5MT0iNDcuMDI4IgogICAgICAgeDE9IjI1LjA1OCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIG9mZnNldD0iLjUiCiAgICAgICAgIGlkPSJzdG9wMTEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDEzIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaWQ9InoiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN5PSIzNS40NzkiCiAgICAgICBjeD0iNy45MzU4IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMS4xNzM0Nzg3LDAsMCwxLjQwMTU0OTIsNDUuMjYxNzI4LC0xMy43OTQ1NjgpIgogICAgICAgcj0iODYuNzA4Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2ZhZmFmYSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDE2IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjYmJiIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMTgiIC8+CiAgICA8L3JhZGlhbEdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpZD0iYWEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN5PSIzLjc1NjEiCiAgICAgICBjeD0iOC44MjQ0IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjE4Mjk5MDMsMCwwLC0xLjEzMTgzNTYsLTEuMDM0MTk2NCw0OC42ODg3NDYpIgogICAgICAgcj0iMzcuNzUyIj4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2EzYTNhMyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDIxIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjOGE4YThhIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMjMiIC8+CiAgICA8L3JhZGlhbEdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpZD0iYWIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN5PSI3LjI2NzkiCiAgICAgICBjeD0iOC4xNDM2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjIwNjk1NzUsMCwwLDIuMTA2MDM4LC05LjM3NjU1NjgsLTkuNTk0Mzk5MykiCiAgICAgICByPSIzOC4xNTkiPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZmZmIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMjYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNmOGY4ZjgiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AyOCIgLz4KICAgIDwvcmFkaWFsR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlkPSJhYyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3k9IjE3IgogICAgICAgY3g9IjgiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDAuNjI1LDAsNi4zNzUpIgogICAgICAgcj0iOCI+CiAgICAgIDxzdG9wCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1vcGFjaXR5PSIwIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzMiIC8+CiAgICA8L3JhZGlhbEdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpZD0icCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3k9IjIyLjEzNyIKICAgICAgIGN4PSIyNCIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC42MDQ1MiwwLDAsMC42MjYwNywxLjQ4MjgsMC45ODMwNikiCiAgICAgICByPSIxOS41Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2VlZWVlYyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM2IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZWVlZWVjIgogICAgICAgICBvZmZzZXQ9Ii41IgogICAgICAgICBpZD0ic3RvcDM4IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZmZmIgogICAgICAgICBvZmZzZXQ9Ii43ODMxMyIKICAgICAgICAgaWQ9InN0b3A0MCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2QzZDdjZiIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDQyIiAvPgogICAgPC9yYWRpYWxHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9InQiCiAgICAgICB5Mj0iNC43Mzk3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4Mj0iNC40ODMyIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjIwOSwwLDAsMS4yNTMzLDIuNjkxOSwxLjcxODkpIgogICAgICAgeTE9IjYuMzExNyIKICAgICAgIHgxPSI2LjA1NTIiPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZWYyOTI5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNDUiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNlZjI5MjkiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDQ3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9InUiCiAgICAgICB5Mj0iMTQuMjc1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4Mj0iOC4xMjI0IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjIwOSwwLDAsMS4yNTMzLDIuNjkxOSwxLjcxODkpIgogICAgICAgeTE9IjE1Ljk2NyIKICAgICAgIHgxPSI2LjQzMDMiPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZWYyOTI5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNlZjI5MjkiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDUyIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9InYiCiAgICAgICB5Mj0iNC4zMTgyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4Mj0iMTcuNDE3IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjIwOSwwLDAsMS4yNTMzLDIuNjkxOSwxLjcxODkpIgogICAgICAgeTE9IjYuNDQzNyIKICAgICAgIHgxPSIxNS4yOTEiPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZWYyOTI5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTUiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNlZjI5MjkiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDU3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9InciCiAgICAgICB5Mj0iMTQuNTQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgyPSIxNC4zNzIiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMjA5LDAsMCwxLjI1MzMsMi42OTE5LDEuNzE4OSkiCiAgICAgICB5MT0iMTUuOTkiCiAgICAgICB4MT0iMTUuODIyIj4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2VmMjkyOSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDYwIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZWYyOTI5IgogICAgICAgICBzdG9wLW9wYWNpdHk9IjAiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A2MiIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlkPSJxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBjeT0iMy4xNTQ5IgogICAgICAgY3g9IjcuNTkyNyIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi43MjQsMCwwLDIuNjMzNCwtMTMuNTYsLTQuODMxMikiCiAgICAgICByPSI4LjQ2MjIiPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZmZmIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNjUiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNmZmYiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iLjMzOTI5IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNjciIC8+CiAgICA8L3JhZGlhbEdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpZD0iciIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3k9IjE2LjE0OSIKICAgICAgIGN4PSIxMC44NjQiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuMjEwMiwwLDAsMi4xMzg5LC0xMi4xMDIsLTE4LjgyMSkiCiAgICAgICByPSI4LjcxNDQiPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZmZmIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNzAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNmZmYiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDcyIiAvPgogICAgPC9yYWRpYWxHcmFkaWVudD4KICA8L2RlZnM+CiAgPGcKICAgICBzdHlsZT0ib3BhY2l0eTowLjQiCiAgICAgaWQ9Imc4MyIKICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjI4NTIyNDYsMCwwLDEuNDA0NDk4NywtNi42Njg4NjcyLC0xNy44NjM1NCkiPgogICAgPHJlY3QKICAgICAgIHN0eWxlPSJmaWxsOnVybCgjeCkiCiAgICAgICBpZD0icmVjdDc3IgogICAgICAgeD0iMzgiCiAgICAgICB5PSI0MCIKICAgICAgIHdpZHRoPSI1IgogICAgICAgaGVpZ2h0PSI3IiAvPgogICAgPHJlY3QKICAgICAgIHN0eWxlPSJmaWxsOnVybCgjeSkiCiAgICAgICBpZD0icmVjdDc5IgogICAgICAgeD0iLTEwIgogICAgICAgeT0iLTQ3IgogICAgICAgd2lkdGg9IjUiCiAgICAgICBoZWlnaHQ9IjciCiAgICAgICB0cmFuc2Zvcm09InNjYWxlKC0xKSIgLz4KICAgIDxyZWN0CiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI3MpIgogICAgICAgaWQ9InJlY3Q4MSIKICAgICAgIHg9IjEwIgogICAgICAgeT0iNDAiCiAgICAgICB3aWR0aD0iMjgiCiAgICAgICBoZWlnaHQ9IjciIC8+CiAgPC9nPgogIDxwYXRoCiAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICBpZD0icGF0aDg1IgogICAgIGRpc3BsYXk9ImJsb2NrIgogICAgIGQ9Ik0gMzEuMjczOTUyLDAuNjI5NyA0LjMzNjI1LDAuNjM5NzUwMDggYyAtMC43Nzc3MjgyLDAgLTEuNTE5NjU2NiwwLjU1NTQ3NDUyIC0xLjUxOTY1NjYsMS4yNTMwOTIwMiBMIDIuOTI0NTE1MSw0NC4yMjMzNDIgYyAwLDAuNjk3NjE4IDAuNjM0MDUzMSwxLjI2MzAzMyAxLjQxMTcyMDIsMS4yNjMwMzMgSCA0NC4xMzM1MDkgYyAwLjc3NzcyOSwwIDEuNDExODQzLC0wLjU2NTQ3IDEuNDExNzIxLC0xLjI2MzAzMyBWIDEuODYwMDcwMSBjIDAsLTAuNjk2NTE0MiAtMC42MzM2OTksLTEuMjI3ODU3NTggLTEuNDExNDc2LC0xLjIyNzg1NzU4IEggMzEuMjc1NDAzIFoiCiAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZGlzcGxheTpibG9jaztmaWxsOnVybCgjeik7c3Ryb2tlOnVybCgjYWEpO3N0cm9rZS13aWR0aDoxLjE1NDkxMTQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kIiAvPgogIDxwYXRoCiAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICBpZD0icGF0aDg3IgogICAgIGRpc3BsYXk9ImJsb2NrIgogICAgIGQ9Ik0gNC4yMTM0MTc0LDEuNzI5MzA5OCBIIDQ0LjAxMTkxMiBjIDAuMTM2NDU5LC0wLjAwNTU4IDAuMzUzMTAxLDAuMDcxNiAwLjMzNjIxNSwwLjIxMDE2NjkgTCA0NC4yNTQxMSw0NC4xOTU2OTMgYyAwLDAuMDkwMiAtMC4wODExNywwLjE2MjgyMyAtMC4xODE5OSwwLjE2MjgyMyBIIDQuNDE2NDgxOSBjIC0wLjEwMDgyMTYsMCAtMC4xODE5OSwtMC4wNzI2MiAtMC4xODE5OSwtMC4xNjI4MjMgTCA0LjAzMjE3MjIsMS44OTI1MDM1IGMgMCwtMC4wOTAyMDMgMC4wODExNjcsLTAuMTYyODIyMiAwLjE4MTk5LC0wLjE2MjgyMjIgeiIKICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmJsb2NrO2ZpbGw6bm9uZTtzdHJva2U6dXJsKCNhYik7c3Ryb2tlLXdpZHRoOjEuMTU0OTExNDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQiIC8+CiAgPHBhdGgKICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojYmFiZGI2O3N0cm9rZS13aWR0aDoxLjE1NDkxMTRweDtzdHJva2UtbGluZWNhcDpyb3VuZCIKICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgIGlkPSJwYXRoMTMxIgogICAgIGQ9Ik0gMTAuMTM2LDcuMTg0MSBIIDM4LjIxOSIgLz4KICA8cGF0aAogICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNiYWJkYjY7c3Ryb2tlLXdpZHRoOjEuMTU0OTExNHB4O3N0cm9rZS1saW5lY2FwOnJvdW5kIgogICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgaWQ9InBhdGgxMzMiCiAgICAgZD0iTSAxMC4xMzYsMTAuNDYxMyBIIDM4LjIxOSIgLz4KICA8ZwogICAgIGlkPSJnMzA5MCIKICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjgyMjc4MTgzLDAsMCwwLjgzNzM1OTQ3LC00NDEuODIyMjYsLTUwLjk3NzgyMykiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7c3Ryb2tlOiMzMDJiMDA7c3Ryb2tlLXdpZHRoOjIuMDE3NjM5NjQ7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gNTgwLjE3MzczLDkxLjgzNjU2MSA1LjA4ODU5LDE3Ljk5OTk5OSAtMTcuMzAxMiwtNiAtMi4wMzU0MywtMy45OTk5OTkgMTAuMTc3MTcsLTEwIHoiCiAgICAgICBpZD0icGF0aDM5NjkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6I2ZjZTk0ZjtzdHJva2U6bm9uZSIKICAgICAgIGQ9Im0gNTU5LjgxOTM4LDcxLjgzNjU1NSAtNC4wNzA4Nyw0IDIwLjM1NDM1LDIwLjAwMDAwNiBjIDAsLTMgMS4wMTc3MiwtNCA0LjA3MDg3LC00IHoiCiAgICAgICBpZD0icGF0aDM4NDMiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDojZWRkNDAwO3N0cm9rZTpub25lIgogICAgICAgZD0ibSA1NTUuNzQ4NTEsNzUuODM2NTQ4IC00LjA3MDg3LDQuMDAwMDEzIDIwLjM1NDM1LDIwIGMgMCwtMyAxLjAxNzcyLC00IDQuMDcwODcsLTQgeiIKICAgICAgIGlkPSJwYXRoMzg0My03IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6I2M0YTAwMDtzdHJva2U6bm9uZSIKICAgICAgIGQ9Im0gNTUxLjY3NzY0LDc5LjgzNjU2MSAtNC4wNzA4Nyw0IDIwLjM1NDM1LDE5Ljk5OTk5OSBjIDAsLTMgMS4wMTc3MiwtMy45OTk5OTkgNC4wNzA4NywtMy45OTk5OTkgeiIKICAgICAgIGlkPSJwYXRoMzg0My01IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2VkZDQwMDtzdHJva2Utd2lkdGg6Mi4wMTc2Mzk2NDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gNTUwLjY1OTkzLDgxLjYzNjU1MyAxOC4zMTg5MSwxOC4wMDAwMSIKICAgICAgIGlkPSJwYXRoMzg4OCIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmY2U5NGY7c3Ryb2tlLXdpZHRoOjIuMDE3NjM5NjQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJNIDU1NC43MzA3OSw3Ny42MzY1NTcgNTczLjA0OTcxLDk1LjYzNjU2IgogICAgICAgaWQ9InBhdGgzODg4LTUiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMzAyYjAwO3N0cm9rZS13aWR0aDoyLjAxNzYzOTY0O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJtIDU1OS44MTkzOCw3MS44MzY1NTggLTQuMDcwODcsNCAyMC4zNTQzNSwyMC4wMDAwMDMgYyAwLC0zIDEuMDE3NzIsLTQgNC4wNzA4NywtNCB6IgogICAgICAgaWQ9InBhdGgzODQzLTUtNiIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMzMDJiMDA7c3Ryb2tlLXdpZHRoOjIuMDE3NjM5NjQ7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gNTU1Ljc0ODUxLDc1LjgzNjU1OCAtNC4wNzA4Nyw0LjAwMDAwMyAyMC4zNTQzNSwyMCBjIDAsLTMgMS4wMTc3MiwtNCA0LjA3MDg3LC00IHoiCiAgICAgICBpZD0icGF0aDM4NDMtNS02LTIiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMzAyYjAwO3N0cm9rZS13aWR0aDoyLjAxNzYzOTY0O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJtIDU1MS42Nzc2NCw3OS44MzY1NjEgLTQuMDcwODcsNCAyMC4zNTQzNSwxOS45OTk5OTkgYyAwLC0zIDEuMDE3NzIsLTMuOTk5OTk5IDQuMDcwODcsLTMuOTk5OTk5IHoiCiAgICAgICBpZD0icGF0aDM4NDMtNS02LTkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDojMzAyYjAwO3N0cm9rZTojMzAyYjAwO3N0cm9rZS13aWR0aDoxLjAwODgxOTgycHg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gNTgzLjIyNjg4LDEwMC44MzY1NiBjIC0yLjAzNTQzLDAgLTUuNjY5MjgsMi41MTYyMyAtNi4xMDYzLDUgbCA4LjE0MTc0LDQgLTIuMDM1NDQsLTggdiAwIgogICAgICAgaWQ9InBhdGgzOTcxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgPC9nPgo8L3N2Zz4K
-#"""
-closeW_b64=\
-"""
+# """
+# PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIGhlaWdodD0iNDgiCiAgIHdpZHRoPSI0OCIKICAgdmVyc2lvbj0iMS4xIgogICBpZD0ic3ZnMTM3IgogICBzb2RpcG9kaTpkb2NuYW1lPSJFZGl0LnN2ZyIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45Mi4wIHIxNTI5OSI+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhMTQxIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZT48L2RjOnRpdGxlPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEiCiAgICAgb2JqZWN0dG9sZXJhbmNlPSIxMCIKICAgICBncmlkdG9sZXJhbmNlPSIxMCIKICAgICBndWlkZXRvbGVyYW5jZT0iMTAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE1MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODAxIgogICAgIGlkPSJuYW1lZHZpZXcxMzkiCiAgICAgc2hvd2dyaWQ9ImZhbHNlIgogICAgIGlua3NjYXBlOnpvb209IjQuOTE2NjY2NyIKICAgICBpbmtzY2FwZTpjeD0iMjQiCiAgICAgaW5rc2NhcGU6Y3k9IjI0IgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJzdmcxMzciIC8+CiAgPGRlZnMKICAgICBpZD0iZGVmczc1Ij4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImEiPgogICAgICA8c3RvcAogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1vcGFjaXR5PSIwIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlkPSJ4IgogICAgICAgeGxpbms6aHJlZj0iI2EiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN5PSI0My41IgogICAgICAgY3g9IjQuOTkzIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjAwMzgsMCwwLDEuNCwyNy45ODgsLTE3LjQpIgogICAgICAgcj0iMi41IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpZD0ieSIKICAgICAgIHhsaW5rOmhyZWY9IiNhIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBjeT0iNDMuNSIKICAgICAgIGN4PSI0Ljk5MyIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi4wMDM4LDAsMCwxLjQsLTIwLjAxMiwtMTA0LjQpIgogICAgICAgcj0iMi41IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0icyIKICAgICAgIHkyPSIzOS45OTkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgyPSIyNS4wNTgiCiAgICAgICB5MT0iNDcuMDI4IgogICAgICAgeDE9IjI1LjA1OCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMCIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIG9mZnNldD0iLjUiCiAgICAgICAgIGlkPSJzdG9wMTEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDEzIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaWQ9InoiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN5PSIzNS40NzkiCiAgICAgICBjeD0iNy45MzU4IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMS4xNzM0Nzg3LDAsMCwxLjQwMTU0OTIsNDUuMjYxNzI4LC0xMy43OTQ1NjgpIgogICAgICAgcj0iODYuNzA4Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2ZhZmFmYSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDE2IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjYmJiIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMTgiIC8+CiAgICA8L3JhZGlhbEdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpZD0iYWEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN5PSIzLjc1NjEiCiAgICAgICBjeD0iOC44MjQ0IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjE4Mjk5MDMsMCwwLC0xLjEzMTgzNTYsLTEuMDM0MTk2NCw0OC42ODg3NDYpIgogICAgICAgcj0iMzcuNzUyIj4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2EzYTNhMyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDIxIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjOGE4YThhIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMjMiIC8+CiAgICA8L3JhZGlhbEdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpZD0iYWIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN5PSI3LjI2NzkiCiAgICAgICBjeD0iOC4xNDM2IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjIwNjk1NzUsMCwwLDIuMTA2MDM4LC05LjM3NjU1NjgsLTkuNTk0Mzk5MykiCiAgICAgICByPSIzOC4xNTkiPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZmZmIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMjYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNmOGY4ZjgiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AyOCIgLz4KICAgIDwvcmFkaWFsR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlkPSJhYyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3k9IjE3IgogICAgICAgY3g9IjgiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDAuNjI1LDAsNi4zNzUpIgogICAgICAgcj0iOCI+CiAgICAgIDxzdG9wCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMSIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1vcGFjaXR5PSIwIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzMiIC8+CiAgICA8L3JhZGlhbEdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpZD0icCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3k9IjIyLjEzNyIKICAgICAgIGN4PSIyNCIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC42MDQ1MiwwLDAsMC42MjYwNywxLjQ4MjgsMC45ODMwNikiCiAgICAgICByPSIxOS41Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2VlZWVlYyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM2IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZWVlZWVjIgogICAgICAgICBvZmZzZXQ9Ii41IgogICAgICAgICBpZD0ic3RvcDM4IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZmZmIgogICAgICAgICBvZmZzZXQ9Ii43ODMxMyIKICAgICAgICAgaWQ9InN0b3A0MCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2QzZDdjZiIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDQyIiAvPgogICAgPC9yYWRpYWxHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9InQiCiAgICAgICB5Mj0iNC43Mzk3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4Mj0iNC40ODMyIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjIwOSwwLDAsMS4yNTMzLDIuNjkxOSwxLjcxODkpIgogICAgICAgeTE9IjYuMzExNyIKICAgICAgIHgxPSI2LjA1NTIiPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZWYyOTI5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNDUiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNlZjI5MjkiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDQ3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9InUiCiAgICAgICB5Mj0iMTQuMjc1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4Mj0iOC4xMjI0IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjIwOSwwLDAsMS4yNTMzLDIuNjkxOSwxLjcxODkpIgogICAgICAgeTE9IjE1Ljk2NyIKICAgICAgIHgxPSI2LjQzMDMiPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZWYyOTI5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNlZjI5MjkiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDUyIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9InYiCiAgICAgICB5Mj0iNC4zMTgyIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4Mj0iMTcuNDE3IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjIwOSwwLDAsMS4yNTMzLDIuNjkxOSwxLjcxODkpIgogICAgICAgeTE9IjYuNDQzNyIKICAgICAgIHgxPSIxNS4yOTEiPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZWYyOTI5IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTUiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNlZjI5MjkiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDU3IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9InciCiAgICAgICB5Mj0iMTQuNTQiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgyPSIxNC4zNzIiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMjA5LDAsMCwxLjI1MzMsMi42OTE5LDEuNzE4OSkiCiAgICAgICB5MT0iMTUuOTkiCiAgICAgICB4MT0iMTUuODIyIj4KICAgICAgPHN0b3AKICAgICAgICAgc3RvcC1jb2xvcj0iI2VmMjkyOSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDYwIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZWYyOTI5IgogICAgICAgICBzdG9wLW9wYWNpdHk9IjAiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A2MiIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlkPSJxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBjeT0iMy4xNTQ5IgogICAgICAgY3g9IjcuNTkyNyIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi43MjQsMCwwLDIuNjMzNCwtMTMuNTYsLTQuODMxMikiCiAgICAgICByPSI4LjQ2MjIiPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZmZmIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNjUiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNmZmYiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iLjMzOTI5IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNjciIC8+CiAgICA8L3JhZGlhbEdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpZD0iciIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgY3k9IjE2LjE0OSIKICAgICAgIGN4PSIxMC44NjQiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuMjEwMiwwLDAsMi4xMzg5LC0xMi4xMDIsLTE4LjgyMSkiCiAgICAgICByPSI4LjcxNDQiPgogICAgICA8c3RvcAogICAgICAgICBzdG9wLWNvbG9yPSIjZmZmIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNzAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0b3AtY29sb3I9IiNmZmYiCiAgICAgICAgIHN0b3Atb3BhY2l0eT0iMCIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDcyIiAvPgogICAgPC9yYWRpYWxHcmFkaWVudD4KICA8L2RlZnM+CiAgPGcKICAgICBzdHlsZT0ib3BhY2l0eTowLjQiCiAgICAgaWQ9Imc4MyIKICAgICB0cmFuc2Zvcm09Im1hdHJpeCgxLjI4NTIyNDYsMCwwLDEuNDA0NDk4NywtNi42Njg4NjcyLC0xNy44NjM1NCkiPgogICAgPHJlY3QKICAgICAgIHN0eWxlPSJmaWxsOnVybCgjeCkiCiAgICAgICBpZD0icmVjdDc3IgogICAgICAgeD0iMzgiCiAgICAgICB5PSI0MCIKICAgICAgIHdpZHRoPSI1IgogICAgICAgaGVpZ2h0PSI3IiAvPgogICAgPHJlY3QKICAgICAgIHN0eWxlPSJmaWxsOnVybCgjeSkiCiAgICAgICBpZD0icmVjdDc5IgogICAgICAgeD0iLTEwIgogICAgICAgeT0iLTQ3IgogICAgICAgd2lkdGg9IjUiCiAgICAgICBoZWlnaHQ9IjciCiAgICAgICB0cmFuc2Zvcm09InNjYWxlKC0xKSIgLz4KICAgIDxyZWN0CiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI3MpIgogICAgICAgaWQ9InJlY3Q4MSIKICAgICAgIHg9IjEwIgogICAgICAgeT0iNDAiCiAgICAgICB3aWR0aD0iMjgiCiAgICAgICBoZWlnaHQ9IjciIC8+CiAgPC9nPgogIDxwYXRoCiAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICBpZD0icGF0aDg1IgogICAgIGRpc3BsYXk9ImJsb2NrIgogICAgIGQ9Ik0gMzEuMjczOTUyLDAuNjI5NyA0LjMzNjI1LDAuNjM5NzUwMDggYyAtMC43Nzc3MjgyLDAgLTEuNTE5NjU2NiwwLjU1NTQ3NDUyIC0xLjUxOTY1NjYsMS4yNTMwOTIwMiBMIDIuOTI0NTE1MSw0NC4yMjMzNDIgYyAwLDAuNjk3NjE4IDAuNjM0MDUzMSwxLjI2MzAzMyAxLjQxMTcyMDIsMS4yNjMwMzMgSCA0NC4xMzM1MDkgYyAwLjc3NzcyOSwwIDEuNDExODQzLC0wLjU2NTQ3IDEuNDExNzIxLC0xLjI2MzAzMyBWIDEuODYwMDcwMSBjIDAsLTAuNjk2NTE0MiAtMC42MzM2OTksLTEuMjI3ODU3NTggLTEuNDExNDc2LC0xLjIyNzg1NzU4IEggMzEuMjc1NDAzIFoiCiAgICAgc3R5bGU9ImNvbG9yOiMwMDAwMDA7ZGlzcGxheTpibG9jaztmaWxsOnVybCgjeik7c3Ryb2tlOnVybCgjYWEpO3N0cm9rZS13aWR0aDoxLjE1NDkxMTQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kIiAvPgogIDxwYXRoCiAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICBpZD0icGF0aDg3IgogICAgIGRpc3BsYXk9ImJsb2NrIgogICAgIGQ9Ik0gNC4yMTM0MTc0LDEuNzI5MzA5OCBIIDQ0LjAxMTkxMiBjIDAuMTM2NDU5LC0wLjAwNTU4IDAuMzUzMTAxLDAuMDcxNiAwLjMzNjIxNSwwLjIxMDE2NjkgTCA0NC4yNTQxMSw0NC4xOTU2OTMgYyAwLDAuMDkwMiAtMC4wODExNywwLjE2MjgyMyAtMC4xODE5OSwwLjE2MjgyMyBIIDQuNDE2NDgxOSBjIC0wLjEwMDgyMTYsMCAtMC4xODE5OSwtMC4wNzI2MiAtMC4xODE5OSwtMC4xNjI4MjMgTCA0LjAzMjE3MjIsMS44OTI1MDM1IGMgMCwtMC4wOTAyMDMgMC4wODExNjcsLTAuMTYyODIyMiAwLjE4MTk5LC0wLjE2MjgyMjIgeiIKICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtkaXNwbGF5OmJsb2NrO2ZpbGw6bm9uZTtzdHJva2U6dXJsKCNhYik7c3Ryb2tlLXdpZHRoOjEuMTU0OTExNDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQiIC8+CiAgPHBhdGgKICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojYmFiZGI2O3N0cm9rZS13aWR0aDoxLjE1NDkxMTRweDtzdHJva2UtbGluZWNhcDpyb3VuZCIKICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgIGlkPSJwYXRoMTMxIgogICAgIGQ9Ik0gMTAuMTM2LDcuMTg0MSBIIDM4LjIxOSIgLz4KICA8cGF0aAogICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNiYWJkYjY7c3Ryb2tlLXdpZHRoOjEuMTU0OTExNHB4O3N0cm9rZS1saW5lY2FwOnJvdW5kIgogICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgaWQ9InBhdGgxMzMiCiAgICAgZD0iTSAxMC4xMzYsMTAuNDYxMyBIIDM4LjIxOSIgLz4KICA8ZwogICAgIGlkPSJnMzA5MCIKICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjgyMjc4MTgzLDAsMCwwLjgzNzM1OTQ3LC00NDEuODIyMjYsLTUwLjk3NzgyMykiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7c3Ryb2tlOiMzMDJiMDA7c3Ryb2tlLXdpZHRoOjIuMDE3NjM5NjQ7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gNTgwLjE3MzczLDkxLjgzNjU2MSA1LjA4ODU5LDE3Ljk5OTk5OSAtMTcuMzAxMiwtNiAtMi4wMzU0MywtMy45OTk5OTkgMTAuMTc3MTcsLTEwIHoiCiAgICAgICBpZD0icGF0aDM5NjkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6I2ZjZTk0ZjtzdHJva2U6bm9uZSIKICAgICAgIGQ9Im0gNTU5LjgxOTM4LDcxLjgzNjU1NSAtNC4wNzA4Nyw0IDIwLjM1NDM1LDIwLjAwMDAwNiBjIDAsLTMgMS4wMTc3MiwtNCA0LjA3MDg3LC00IHoiCiAgICAgICBpZD0icGF0aDM4NDMiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDojZWRkNDAwO3N0cm9rZTpub25lIgogICAgICAgZD0ibSA1NTUuNzQ4NTEsNzUuODM2NTQ4IC00LjA3MDg3LDQuMDAwMDEzIDIwLjM1NDM1LDIwIGMgMCwtMyAxLjAxNzcyLC00IDQuMDcwODcsLTQgeiIKICAgICAgIGlkPSJwYXRoMzg0My03IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6I2M0YTAwMDtzdHJva2U6bm9uZSIKICAgICAgIGQ9Im0gNTUxLjY3NzY0LDc5LjgzNjU2MSAtNC4wNzA4Nyw0IDIwLjM1NDM1LDE5Ljk5OTk5OSBjIDAsLTMgMS4wMTc3MiwtMy45OTk5OTkgNC4wNzA4NywtMy45OTk5OTkgeiIKICAgICAgIGlkPSJwYXRoMzg0My01IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2VkZDQwMDtzdHJva2Utd2lkdGg6Mi4wMTc2Mzk2NDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gNTUwLjY1OTkzLDgxLjYzNjU1MyAxOC4zMTg5MSwxOC4wMDAwMSIKICAgICAgIGlkPSJwYXRoMzg4OCIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmY2U5NGY7c3Ryb2tlLXdpZHRoOjIuMDE3NjM5NjQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJNIDU1NC43MzA3OSw3Ny42MzY1NTcgNTczLjA0OTcxLDk1LjYzNjU2IgogICAgICAgaWQ9InBhdGgzODg4LTUiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMzAyYjAwO3N0cm9rZS13aWR0aDoyLjAxNzYzOTY0O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJtIDU1OS44MTkzOCw3MS44MzY1NTggLTQuMDcwODcsNCAyMC4zNTQzNSwyMC4wMDAwMDMgYyAwLC0zIDEuMDE3NzIsLTQgNC4wNzA4NywtNCB6IgogICAgICAgaWQ9InBhdGgzODQzLTUtNiIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMzMDJiMDA7c3Ryb2tlLXdpZHRoOjIuMDE3NjM5NjQ7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gNTU1Ljc0ODUxLDc1LjgzNjU1OCAtNC4wNzA4Nyw0LjAwMDAwMyAyMC4zNTQzNSwyMCBjIDAsLTMgMS4wMTc3MiwtNCA0LjA3MDg3LC00IHoiCiAgICAgICBpZD0icGF0aDM4NDMtNS02LTIiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMzAyYjAwO3N0cm9rZS13aWR0aDoyLjAxNzYzOTY0O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJtIDU1MS42Nzc2NCw3OS44MzY1NjEgLTQuMDcwODcsNCAyMC4zNTQzNSwxOS45OTk5OTkgYyAwLC0zIDEuMDE3NzIsLTMuOTk5OTk5IDQuMDcwODcsLTMuOTk5OTk5IHoiCiAgICAgICBpZD0icGF0aDM4NDMtNS02LTkiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDojMzAyYjAwO3N0cm9rZTojMzAyYjAwO3N0cm9rZS13aWR0aDoxLjAwODgxOTgycHg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gNTgzLjIyNjg4LDEwMC44MzY1NiBjIC0yLjAzNTQzLDAgLTUuNjY5MjgsMi41MTYyMyAtNi4xMDYzLDUgbCA4LjE0MTc0LDQgLTIuMDM1NDQsLTggdiAwIgogICAgICAgaWQ9InBhdGgzOTcxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiIC8+CiAgPC9nPgo8L3N2Zz4K
+# """
+closeW_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0IgogICBoZWlnaHQ9IjY0IgogICBpZD0ic3ZnMiIKICAgdmVyc2lvbj0iMS4xIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ4LjUgcjEwMDQwIgogICBzb2RpcG9kaTpkb2NuYW1lPSJlZGl0X0NhbmNlbC5zdmciCiAgIHZpZXdCb3g9IjAgMCA2NCA2NCI+CiAgPGRlZnMKICAgICBpZD0iZGVmczQiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc5IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIj4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODgxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg4MyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2OSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODcxIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMzg3MyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4NjkiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODc1IgogICAgICAgeDE9Ii00NSIKICAgICAgIHkxPSIxMDQ0LjM2MjIiCiAgICAgICB4Mj0iLTU1IgogICAgICAgeTI9Ijk5NC4zNjIxOCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgwLjg2NjQ3NzI3LDAsMCwwLjg2NjQ3NzM5LDczLjY1MzQwOSwxMzYuMzAzOTEpIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODc5IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg3NyIKICAgICAgIHgxPSItNDUiCiAgICAgICB5MT0iMTA0NC4zNjIyIgogICAgICAgeDI9Ii01NSIKICAgICAgIHkyPSI5OTQuMzYyMTgiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44NjY0NzcyNywwLDAsMC44NjY0NzczOSw3My42NTM0MDksMTM2LjMwMzkxKSIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjYuNTU3NzM4IgogICAgIGlua3NjYXBlOmN4PSI1MC4yNzE5NTgiCiAgICAgaW5rc2NhcGU6Y3k9IjMyLjkwMDkyNCIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTU5OCIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI4MzYiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjAiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjI3IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjAiCiAgICAgaW5rc2NhcGU6c25hcC1nbG9iYWw9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9InRydWUiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMTE1MjEiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgZG90dGVkPSJmYWxzZSIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTciPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOnRpdGxlPjwvZGM6dGl0bGU+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIKICAgICBpZD0ibGF5ZXIxIgogICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAsLTk4OC4zNjIxOCkiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMyODAwMDA7c3Ryb2tlLXdpZHRoOjE2O3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gMTMsMTAwMS4zNjIyIDM4LjEyNSwzOC4xMjUiCiAgICAgICBpZD0icGF0aDMwMDIiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMjgwMDAwO3N0cm9rZS13aWR0aDoxNjtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJNIDUxLjEyNSwxMDAxLjM2MjIgMTMsMTAzOS40ODcyIgogICAgICAgaWQ9InBhdGgzMDAyLTYiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDoxMjtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBkPSJtIDEzLDEwMDEuMzYyMiAzOC4xMjUsMzguMTI1IgogICAgICAgaWQ9InBhdGgzMDAyLTciCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZWYyOTI5O3N0cm9rZS13aWR0aDoxMjtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBkPSJNIDUxLjEyNSwxMDAxLjM2MjIgMTMsMTAzOS40ODcyIgogICAgICAgaWQ9InBhdGgzMDAyLTYtNSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOnVybCgjbGluZWFyR3JhZGllbnQzODc3KTtzdHJva2Utd2lkdGg6ODtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBkPSJtIDEzLDEwMDEuMzYyMiAzOC4xMjUsMzguMTI1IgogICAgICAgaWQ9InBhdGgzMDAyLTctNiIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOnVybCgjbGluZWFyR3JhZGllbnQzODc1KTtzdHJva2Utd2lkdGg6ODtzdHJva2UtbGluZWNhcDpzcXVhcmU7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmUiCiAgICAgICBkPSJNIDUxLjEyNSwxMDAxLjM2MjIgMTMsMTAzOS40ODcyIgogICAgICAgaWQ9InBhdGgzMDAyLTYtNS0yIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgPC9nPgo8L3N2Zz4K
"""
-un_dock_b64=\
-"""
+un_dock_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpvc2I9Imh0dHA6Ly93d3cub3BlbnN3YXRjaGJvb2sub3JnL3VyaS8yMDA5L29zYiIKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMCIKICAgeD0iMC4wMDAwMDAwIgogICB5PSIwLjAwMDAwMDAiCiAgIHdpZHRoPSI2NCIKICAgaGVpZ2h0PSI2NCIKICAgaWQ9InN2ZzExMzAwIgogICBzb2RpcG9kaTp2ZXJzaW9uPSIwLjMyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ4LjQgcjk5MzkiCiAgIHNvZGlwb2RpOmRvY25hbWU9InVuLWRvY2suc3ZnIj4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGE2NiI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGUgLz4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5Db3JleSBXb29kd29ydGg8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICAgIDxjYzpsaWNlbnNlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS8yLjAvIiAvPgogICAgICAgIDxkYzpzb3VyY2U+aHR0cDovL2ppbW1hYy5tdXNpY2hhbGwuY3o8L2RjOnNvdXJjZT4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkpha3ViIFN0ZWluZXI8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICA8cmRmOkJhZz4KICAgICAgICAgICAgPHJkZjpsaT5uZXc8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5pbnNlcnQ8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT53aW5kb3c8L3JkZjpsaT4KICAgICAgICAgIDwvcmRmOkJhZz4KICAgICAgICA8L2RjOnN1YmplY3Q+CiAgICAgIDwvY2M6V29yaz4KICAgICAgPGNjOkxpY2Vuc2UKICAgICAgICAgcmRmOmFib3V0PSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1zYS8yLjAvIj4KICAgICAgICA8Y2M6cGVybWl0cwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvUmVwcm9kdWN0aW9uIiAvPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9EaXN0cmlidXRpb24iIC8+CiAgICAgICAgPGNjOnJlcXVpcmVzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9Ob3RpY2UiIC8+CiAgICAgICAgPGNjOnJlcXVpcmVzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vd2ViLnJlc291cmNlLm9yZy9jYy9BdHRyaWJ1dGlvbiIgLz4KICAgICAgICA8Y2M6cGVybWl0cwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvRGVyaXZhdGl2ZVdvcmtzIiAvPgogICAgICAgIDxjYzpyZXF1aXJlcwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3dlYi5yZXNvdXJjZS5vcmcvY2MvU2hhcmVBbGlrZSIgLz4KICAgICAgPC9jYzpMaWNlbnNlPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjEiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGlkPSJiYXNlIgogICAgIGlua3NjYXBlOnpvb209IjUuNjU2ODU0MiIKICAgICBpbmtzY2FwZTpjeD0iLTIuMzI3NTAwNSIKICAgICBpbmtzY2FwZTpjeT0iMTkuMzY5NDQxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOSIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTkiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMTEzMDAiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9ImZhbHNlIgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMzAxNiIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8ZGVmcwogICAgIGlkPSJkZWZzMyI+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQ2MzMiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzMzMzMzO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQ2MjkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMzMzMzMzM7c3RvcC1vcGFjaXR5OjA7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDYzMSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MzIiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDQ2MjQiCiAgICAgICAgIG9mZnNldD0iMC4wMDAwMDAwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eToxIiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDQ2MjYiCiAgICAgICAgIG9mZnNldD0iMS4wMDAwMDAwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZDNkN2NmO3N0b3Atb3BhY2l0eToxIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTA2MCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDUwMzEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTIuNzc0Mzg5LDAsMCwxLjk2OTcwNiwxMTIuNzYyMywtODcyLjg4NTQpIgogICAgICAgY3g9IjYwNS43MTQyOSIKICAgICAgIGN5PSI0ODYuNjQ3ODkiCiAgICAgICBmeD0iNjA1LjcxNDI5IgogICAgICAgZnk9IjQ4Ni42NDc4OSIKICAgICAgIHI9IjExNy4xNDI4NiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50NTA2MCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOmJsYWNrO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDUwNjIiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOmJsYWNrO3N0b3Atb3BhY2l0eTowOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDUwNjQiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1MDYwIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50NTAyOSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjc3NDM4OSwwLDAsMS45Njk3MDYsLTE4OTEuNjMzLC04NzIuODg1NCkiCiAgICAgICBjeD0iNjA1LjcxNDI5IgogICAgICAgY3k9IjQ4Ni42NDc4OSIKICAgICAgIGZ4PSI2MDUuNzE0MjkiCiAgICAgICBmeT0iNDg2LjY0Nzg5IgogICAgICAgcj0iMTE3LjE0Mjg2IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ1MDQ4Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6YmxhY2s7c3RvcC1vcGFjaXR5OjA7IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNTA1MCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3A1MDU2IgogICAgICAgICBvZmZzZXQ9IjAuNSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6YmxhY2s7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjpibGFjaztzdG9wLW9wYWNpdHk6MDsiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3A1MDUyIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTA0OCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDUwMjciCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi43NzQzODksMCwwLDEuOTY5NzA2LC0xODkyLjE3OSwtODcyLjg4NTQpIgogICAgICAgeDE9IjMwMi44NTcxNSIKICAgICAgIHkxPSIzNjYuNjQ3ODkiCiAgICAgICB4Mj0iMzAyLjg1NzE1IgogICAgICAgeTI9IjYwOS41MDUwNyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MTI1MTIiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eToxLjAwMDAwMDAiCiAgICAgICAgIG9mZnNldD0iMC4wMDAwMDAwIgogICAgICAgICBpZD0ic3RvcDEyNTEzIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmNTIwO3N0b3Atb3BhY2l0eTowLjg5MTA4OTA4IgogICAgICAgICBvZmZzZXQ9IjAuNTAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wMTI1MTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmYzMDA7c3RvcC1vcGFjaXR5OjAuMDAwMDAwMCIKICAgICAgICAgb2Zmc2V0PSIxLjAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wMTI1MTQiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0ODE2Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzM0NjVhNDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwLjAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wNDgxOCIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzcyOWZjZjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxLjAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wNDgyMCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQ4MDgiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMDAwMDAwO3N0b3Atb3BhY2l0eToxLjAwMDAwMDAiCiAgICAgICAgIG9mZnNldD0iMC4wMDAwMDAwIgogICAgICAgICBpZD0ic3RvcDQ4MTAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDAwMDA7c3RvcC1vcGFjaXR5OjAuMDAwMDAwMCIKICAgICAgICAgb2Zmc2V0PSIxLjAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wNDgxMiIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MzItNSIKICAgICAgIG9zYjpwYWludD0iZ3JhZGllbnQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAuMDAwMDAwMCIKICAgICAgICAgaWQ9InN0b3AzODM0IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZDNkN2NmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEuMDAwMDAwMCIKICAgICAgICAgaWQ9InN0b3AzODM2IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDgwOCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDEzNzIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMS45NDU3MzQsMCwwLDAuNjI3Mjc0LC05LjYyODQ1NSwyNC4yNTkyMSkiCiAgICAgICBjeD0iMTcuMzY4MzExIgogICAgICAgY3k9IjI1LjY4MTk0MiIKICAgICAgIGZ4PSIxNy4zNjgzMTEiCiAgICAgICBmeT0iMjUuNjgxOTQyIgogICAgICAgcj0iMTEuNzk5ODQ1IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODMyLTUiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyMjY3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDMuMjUzOTM1LDAsMCwzLjI5NTQ1MTcsLTE2LjM2NDA3NCwtMjQuNTQ2OTQzKSIKICAgICAgIHgxPSIxMy44MTczOTkiCiAgICAgICB5MT0iOC42NjQ3ODI1IgogICAgICAgeDI9IjE3Ljg4MDY4IgogICAgICAgeTI9IjIxLjc2NzU3OCIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTA2MCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDUwMjktOCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjc3NDM4OSwwLDAsMS45Njk3MDYsLTE4OTEuNjMzLC04NzIuODg1NCkiCiAgICAgICBjeD0iNjA1LjcxNDI5IgogICAgICAgY3k9IjQ4Ni42NDc4OSIKICAgICAgIGZ4PSI2MDUuNzE0MjkiCiAgICAgICBmeT0iNDg2LjY0Nzg5IgogICAgICAgcj0iMTE3LjE0Mjg2IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1MDYwIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50NTAzMS0yIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0yLjc3NDM4OSwwLDAsMS45Njk3MDYsMTEyLjc2MjMsLTg3Mi44ODU0KSIKICAgICAgIGN4PSI2MDUuNzE0MjkiCiAgICAgICBjeT0iNDg2LjY0Nzg5IgogICAgICAgZng9IjYwNS43MTQyOSIKICAgICAgIGZ5PSI0ODYuNjQ3ODkiCiAgICAgICByPSIxMTcuMTQyODYiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNDgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQxMTIiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi43NzQzODksMCwwLDEuOTY5NzA2LC0xODkyLjE3OSwtODcyLjg4NTQpIgogICAgICAgeDE9IjMwMi44NTcxNSIKICAgICAgIHkxPSIzNjYuNjQ3ODkiCiAgICAgICB4Mj0iMzAyLjg1NzE1IgogICAgICAgeTI9IjYwOS41MDUwNyIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDYzMyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQ2MzUiCiAgICAgICB4MT0iNTguNDQ2OTY4IgogICAgICAgeTE9IjU4Ljc3NjU0NiIKICAgICAgIHgyPSIzMy43NTQ1NTkiCiAgICAgICB5Mj0iMTIuNDYxMDUxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNDgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDQ5IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNzc0Mzg5LDAsMCwxLjk2OTcwNiwtMTg5Mi4xNzksLTg3Mi44ODU0KSIKICAgICAgIHgxPSIzMDIuODU3MTUiCiAgICAgICB5MT0iMzY2LjY0Nzg5IgogICAgICAgeDI9IjMwMi44NTcxNSIKICAgICAgIHkyPSI2MDkuNTA1MDciIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNjAiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMDUxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNzc0Mzg5LDAsMCwxLjk2OTcwNiwtMTg5MS42MzMsLTg3Mi44ODU0KSIKICAgICAgIGN4PSI2MDUuNzE0MjkiCiAgICAgICBjeT0iNDg2LjY0Nzg5IgogICAgICAgZng9IjYwNS43MTQyOSIKICAgICAgIGZ5PSI0ODYuNjQ3ODkiCiAgICAgICByPSIxMTcuMTQyODYiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNjAiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMDUzIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0yLjc3NDM4OSwwLDAsMS45Njk3MDYsMTEyLjc2MjMsLTg3Mi44ODU0KSIKICAgICAgIGN4PSI2MDUuNzE0MjkiCiAgICAgICBjeT0iNDg2LjY0Nzg5IgogICAgICAgZng9IjYwNS43MTQyOSIKICAgICAgIGZ5PSI0ODYuNjQ3ODkiCiAgICAgICByPSIxMTcuMTQyODYiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4MzItNSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwNTUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMy4yNTM5MzUsMCwwLDMuMjk1NDUxNywtMTYuMzY0MDc0LC0yNC41NDY5NDMpIgogICAgICAgeDE9IjEzLjgxNzM5OSIKICAgICAgIHkxPSI4LjY2NDc4MjUiCiAgICAgICB4Mj0iMTcuODgwNjgiCiAgICAgICB5Mj0iMjEuNzY3NTc4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1MDQ4IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA1NyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjc3NDM4OSwwLDAsMS45Njk3MDYsLTE4OTIuMTc5LC04NzIuODg1NCkiCiAgICAgICB4MT0iMzAyLjg1NzE1IgogICAgICAgeTE9IjM2Ni42NDc4OSIKICAgICAgIHgyPSIzMDIuODU3MTUiCiAgICAgICB5Mj0iNjA5LjUwNTA3IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1MDYwIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzA1OSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgyLjc3NDM4OSwwLDAsMS45Njk3MDYsLTE4OTEuNjMzLC04NzIuODg1NCkiCiAgICAgICBjeD0iNjA1LjcxNDI5IgogICAgICAgY3k9IjQ4Ni42NDc4OSIKICAgICAgIGZ4PSI2MDUuNzE0MjkiCiAgICAgICBmeT0iNDg2LjY0Nzg5IgogICAgICAgcj0iMTE3LjE0Mjg2IiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ1MDYwIgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzA2MSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgtMi43NzQzODksMCwwLDEuOTY5NzA2LDExMi43NjIzLC04NzIuODg1NCkiCiAgICAgICBjeD0iNjA1LjcxNDI5IgogICAgICAgY3k9IjQ4Ni42NDc4OSIKICAgICAgIGZ4PSI2MDUuNzE0MjkiCiAgICAgICBmeT0iNDg2LjY0Nzg5IgogICAgICAgcj0iMTE3LjE0Mjg2IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0NjMzIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA2MyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjU4LjQ0Njk2OCIKICAgICAgIHkxPSI1OC43NzY1NDYiCiAgICAgICB4Mj0iMzMuNzU0NTU5IgogICAgICAgeTI9IjEyLjQ2MTA1MSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTA0OCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwODMiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi43NzQzODksMCwwLDEuOTY5NzA2LC0xODkyLjE3OSwtODcyLjg4NTQpIgogICAgICAgeDE9IjMwMi44NTcxNSIKICAgICAgIHkxPSIzNjYuNjQ3ODkiCiAgICAgICB4Mj0iMzAyLjg1NzE1IgogICAgICAgeTI9IjYwOS41MDUwNyIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTA2MCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMwODUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMi43NzQzODksMCwwLDEuOTY5NzA2LC0xODkxLjYzMywtODcyLjg4NTQpIgogICAgICAgY3g9IjYwNS43MTQyOSIKICAgICAgIGN5PSI0ODYuNjQ3ODkiCiAgICAgICBmeD0iNjA1LjcxNDI5IgogICAgICAgZnk9IjQ4Ni42NDc4OSIKICAgICAgIHI9IjExNy4xNDI4NiIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NTA2MCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMwODciCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTIuNzc0Mzg5LDAsMCwxLjk2OTcwNiwxMTIuNzYyMywtODcyLjg4NTQpIgogICAgICAgY3g9IjYwNS43MTQyOSIKICAgICAgIGN5PSI0ODYuNjQ3ODkiCiAgICAgICBmeD0iNjA1LjcxNDI5IgogICAgICAgZnk9IjQ4Ni42NDc4OSIKICAgICAgIHI9IjExNy4xNDI4NiIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDYzMyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwODkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSI1OC40NDY5NjgiCiAgICAgICB5MT0iNTguNzc2NTQ2IgogICAgICAgeDI9IjMzLjc1NDU1OSIKICAgICAgIHkyPSIxMi40NjEwNTEiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNDgiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMDkxIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNzc0Mzg5LDAsMCwxLjk2OTcwNiwtMTg5Mi4xNzksLTg3Mi44ODU0KSIKICAgICAgIHgxPSIzMDIuODU3MTUiCiAgICAgICB5MT0iMzY2LjY0Nzg5IgogICAgICAgeDI9IjMwMi44NTcxNSIKICAgICAgIHkyPSI2MDkuNTA1MDciIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNjAiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMDkzIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuNzc0Mzg5LDAsMCwxLjk2OTcwNiwtMTg5MS42MzMsLTg3Mi44ODU0KSIKICAgICAgIGN4PSI2MDUuNzE0MjkiCiAgICAgICBjeT0iNDg2LjY0Nzg5IgogICAgICAgZng9IjYwNS43MTQyOSIKICAgICAgIGZ5PSI0ODYuNjQ3ODkiCiAgICAgICByPSIxMTcuMTQyODYiIC8+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDUwNjAiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQzMDk1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0yLjc3NDM4OSwwLDAsMS45Njk3MDYsMTEyLjc2MjMsLTg3Mi44ODU0KSIKICAgICAgIGN4PSI2MDUuNzE0MjkiCiAgICAgICBjeT0iNDg2LjY0Nzg5IgogICAgICAgZng9IjYwNS43MTQyOSIKICAgICAgIGZ5PSI0ODYuNjQ3ODkiCiAgICAgICByPSIxMTcuMTQyODYiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4MzItNSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDMwOTciCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMy4yNTM5MzUsMCwwLDMuMjk1NDUxNywtMTYuMzY0MDc0LC0yNC41NDY5NDMpIgogICAgICAgeDE9IjEzLjgxNzM5OSIKICAgICAgIHkxPSI4LjY2NDc4MjUiCiAgICAgICB4Mj0iMTcuODgwNjgiCiAgICAgICB5Mj0iMjEuNzY3NTc4IiAvPgogIDwvZGVmcz4KICA8ZwogICAgIGlkPSJnMzA2NSIKICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMS4wMjA0MzMzLC0xLjgwNzcwODgpIj4KICAgIDxnCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjg1NzM3NSwwLDAsMC44NTczNzUsNi41OTQ2MDc4LDYuNjgwMDQxMikiCiAgICAgICBpZD0iZzMwNDAiPgogICAgICA8ZwogICAgICAgICBpZD0iZzQ2NDMiPgogICAgICAgIDxnCiAgICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC4wMjg0NDcxMiwwLDAsMC4wMTg4NjY2NSw2MS44NTY3MDYsNTkuMjAwODI2KSIKICAgICAgICAgICBpZD0iZzUwMjItMiIKICAgICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmUiPgogICAgICAgICAgPHJlY3QKICAgICAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjAuNDAyMDYxODU7Y29sb3I6IzAwMDAwMDtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMDgzKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MTttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgICAgICAgIGlkPSJyZWN0NDE3My0xIgogICAgICAgICAgICAgd2lkdGg9IjEzMzkuNjMzNSIKICAgICAgICAgICAgIGhlaWdodD0iNDc4LjM1NzE4IgogICAgICAgICAgICAgeD0iLTE1NTkuMjUyMyIKICAgICAgICAgICAgIHk9Ii0xNTAuNjk2ODUiIC8+CiAgICAgICAgICA8cGF0aAogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjAuNDAyMDYxODU7Y29sb3I6IzAwMDAwMDtmaWxsOnVybCgjcmFkaWFsR3JhZGllbnQzMDg1KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MTttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgICAgICAgIGQ9Im0gLTIxOS42MTg3NiwtMTUwLjY4MDM4IGMgMCwwIDAsNDc4LjMzMDc5IDAsNDc4LjMzMDc5IDE0Mi44NzQxNjYsMC45MDA0NSAzNDUuNDAwMjIsLTEwNy4xNjk2NiAzNDUuNDAwMTQsLTIzOS4xOTYxNzUgMCwtMTMyLjAyNjUzNyAtMTU5LjQzNjgxNiwtMjM5LjEzNDU5NSAtMzQ1LjQwMDE0LC0yMzkuMTM0NjE1IHoiCiAgICAgICAgICAgICBpZD0icGF0aDUwNTgtMCIKICAgICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjYyIgLz4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjIgogICAgICAgICAgICAgaWQ9InBhdGg1MDE4LTUiCiAgICAgICAgICAgICBkPSJtIC0xNTU5LjI1MjMsLTE1MC42ODAzOCBjIDAsMCAwLDQ3OC4zMzA3OSAwLDQ3OC4zMzA3OSAtMTQyLjg3NDIsMC45MDA0NSAtMzQ1LjQwMDIsLTEwNy4xNjk2NiAtMzQ1LjQwMDIsLTIzOS4xOTYxNzUgMCwtMTMyLjAyNjUzNyAxNTkuNDM2OCwtMjM5LjEzNDU5NSAzNDUuNDAwMiwtMjM5LjEzNDYxNSB6IgogICAgICAgICAgICAgc3R5bGU9Im9wYWNpdHk6MC40MDIwNjE4NTtjb2xvcjojMDAwMDAwO2ZpbGw6dXJsKCNyYWRpYWxHcmFkaWVudDMwODcpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlIiAvPgogICAgICAgIDwvZz4KICAgICAgICA8cmVjdAogICAgICAgICAgIGlkPSJyZWN0MzgxOC04IgogICAgICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2ZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMwODkpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTojOGQ4ZDhkO3N0cm9rZS13aWR0aDoxLjgwNDk5OTk1O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgICAgICB5PSIxMC4zMzAxOCIKICAgICAgICAgICB4PSIxMC4zODIzMjEiCiAgICAgICAgICAgcnk9IjEuNDExOTg0OSIKICAgICAgICAgICByeD0iMS4yODY1ODAzIgogICAgICAgICAgIGhlaWdodD0iNTIuMzQ1MDAxIgogICAgICAgICAgIHdpZHRoPSI1Mi4zNDUwMDEiIC8+CiAgICAgICAgPHJlY3QKICAgICAgICAgICBpZD0icmVjdDQ5NjItNyIKICAgICAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjEuODA0OTk5OTU7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgICAgIHk9IjEyLjEzNTE4IgogICAgICAgICAgIHg9IjEyLjE4NzMyMiIKICAgICAgICAgICByeT0iMCIKICAgICAgICAgICByeD0iMCIKICAgICAgICAgICBoZWlnaHQ9IjQ4LjczNTAwMSIKICAgICAgICAgICB3aWR0aD0iNDguNzM1MDAxIiAvPgogICAgICA8L2c+CiAgICA8L2c+CiAgICA8ZwogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMC44NTczNzUsMCwwLDAuODU3Mzc1LDQuMDA4NDg0OSw0LjExNjg4NjQpIgogICAgICAgaWQ9ImczMDMxIj4KICAgICAgPGcKICAgICAgICAgaWQ9ImcxNDYiCiAgICAgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAuNCwwKSI+CiAgICAgICAgPGcKICAgICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjAyODQ0NzEyLDAsMCwwLjAxODg2NjY1LDUzLjAwNjk0NSw1MC42NjA3NTcpIgogICAgICAgICAgIGlkPSJnNTAyMiIKICAgICAgICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmUiPgogICAgICAgICAgPHJlY3QKICAgICAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjAuNDAyMDYxODU7Y29sb3I6IzAwMDAwMDtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMDkxKTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MTttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZSIKICAgICAgICAgICAgIGlkPSJyZWN0NDE3MyIKICAgICAgICAgICAgIHdpZHRoPSIxMzM5LjYzMzUiCiAgICAgICAgICAgICBoZWlnaHQ9IjQ3OC4zNTcxOCIKICAgICAgICAgICAgIHg9Ii0xNTU5LjI1MjMiCiAgICAgICAgICAgICB5PSItMTUwLjY5Njg1IiAvPgogICAgICAgICAgPHBhdGgKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBzdHlsZT0ib3BhY2l0eTowLjQwMjA2MTg1O2NvbG9yOiMwMDAwMDA7ZmlsbDp1cmwoI3JhZGlhbEdyYWRpZW50MzA5Myk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjE7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGUiCiAgICAgICAgICAgICBkPSJtIC0yMTkuNjE4NzYsLTE1MC42ODAzOCBjIDAsMCAwLDQ3OC4zMzA3OSAwLDQ3OC4zMzA3OSAxNDIuODc0MTY2LDAuOTAwNDUgMzQ1LjQwMDIyLC0xMDcuMTY5NjYgMzQ1LjQwMDE0LC0yMzkuMTk2MTc1IDAsLTEzMi4wMjY1MzcgLTE1OS40MzY4MTYsLTIzOS4xMzQ1OTUgLTM0NS40MDAxNCwtMjM5LjEzNDYxNSB6IgogICAgICAgICAgICAgaWQ9InBhdGg1MDU4IgogICAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjIiAvPgogICAgICAgICAgPHBhdGgKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2MiCiAgICAgICAgICAgICBpZD0icGF0aDUwMTgiCiAgICAgICAgICAgICBkPSJtIC0xNTU5LjI1MjMsLTE1MC42ODAzOCBjIDAsMCAwLDQ3OC4zMzA3OSAwLDQ3OC4zMzA3OSAtMTQyLjg3NDIsMC45MDA0NSAtMzQ1LjQwMDIsLTEwNy4xNjk2NiAtMzQ1LjQwMDIsLTIzOS4xOTYxNzUgMCwtMTMyLjAyNjUzNyAxNTkuNDM2OCwtMjM5LjEzNDU5NSAzNDUuNDAwMiwtMjM5LjEzNDYxNSB6IgogICAgICAgICAgICAgc3R5bGU9Im9wYWNpdHk6MC40MDIwNjE4NTtjb2xvcjojMDAwMDAwO2ZpbGw6dXJsKCNyYWRpYWxHcmFkaWVudDMwOTUpO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlIiAvPgogICAgICAgIDwvZz4KICAgICAgICA8cmVjdAogICAgICAgICAgIGlkPSJyZWN0MzgxOCIKICAgICAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOnVybCgjbGluZWFyR3JhZGllbnQzMDk3KTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6IzhkOGQ4ZDtzdHJva2Utd2lkdGg6MS44MDQ5OTk5NTtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGUiCiAgICAgICAgICAgeT0iMS43OTAxMTE0IgogICAgICAgICAgIHg9IjEuNTMyNTYzMSIKICAgICAgICAgICByeT0iMS40MTE5ODQ5IgogICAgICAgICAgIHJ4PSIxLjI4NjU4MDMiCiAgICAgICAgICAgaGVpZ2h0PSI1Mi4zNDUwMDEiCiAgICAgICAgICAgd2lkdGg9IjUyLjM0NTAwMSIgLz4KICAgICAgICA8cmVjdAogICAgICAgICAgIGlkPSJyZWN0NDk2MiIKICAgICAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjEuODA0OTk5OTU7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlIgogICAgICAgICAgIHk9IjMuNTk1MTExNCIKICAgICAgICAgICB4PSIzLjMzNzU2MyIKICAgICAgICAgICByeT0iMCIKICAgICAgICAgICByeD0iMCIKICAgICAgICAgICBoZWlnaHQ9IjQ4LjczNTAwMSIKICAgICAgICAgICB3aWR0aD0iNDguNzM1MDAxIiAvPgogICAgICA8L2c+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K
"""
-dock_right_b64=\
-"""
+dock_right_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB3aWR0aD0iNjRweCIKICAgaGVpZ2h0PSI2NHB4IgogICBpZD0ic3ZnMjk4NSIKICAgdmVyc2lvbj0iMS4xIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ4LjQgcjk5MzkiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImRvY2stbGVmdC5zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMyOTg3IiAvPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI1LjA5NjgzMTIiCiAgICAgaW5rc2NhcGU6Y3g9Ii01OS45NzI4ODUiCiAgICAgaW5rc2NhcGU6Y3k9IjE2LjE5MzQxMyIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjI1NjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTM2MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTkiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii05IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9ImZhbHNlIj4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDI5ODciCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhMjk5MCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGU+PC9kYzp0aXRsZT4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlt5b3Jpa3ZhbmhhdnJlXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6dGl0bGU+QXJjaF9TZWN0aW9uUGxhbmVfVHJlZTwvZGM6dGl0bGU+CiAgICAgICAgPGRjOmRhdGU+MjAxMS0xMi0wNjwvZGM6ZGF0ZT4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9BcmNoL1Jlc291cmNlcy9pY29ucy9BcmNoX1NlY3Rpb25QbGFuZV9UcmVlLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8Y2M6bGljZW5zZT5odHRwczovL3d3dy5nbnUub3JnL2NvcHlsZWZ0L2xlc3Nlci5odG1sPC9jYzpsaWNlbnNlPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPHBhdGgKICAgICAgIHNvZGlwb2RpOnR5cGU9InN0YXIiCiAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOiM4MDgwODA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOiM0ZDRkNGQ7c3Ryb2tlLXdpZHRoOjEuNTc0ODgyMjc7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiCiAgICAgICBpZD0icGF0aDI5OTciCiAgICAgICBzb2RpcG9kaTpzaWRlcz0iMyIKICAgICAgIHNvZGlwb2RpOmN4PSIyMiIKICAgICAgIHNvZGlwb2RpOmN5PSIxNy4wOTA5MDgiCiAgICAgICBzb2RpcG9kaTpyMT0iMjAuNDMyNTEyIgogICAgICAgc29kaXBvZGk6cjI9IjEwLjIxNjI1NyIKICAgICAgIHNvZGlwb2RpOmFyZzE9IjIuMDk0Mzk1MSIKICAgICAgIHNvZGlwb2RpOmFyZzI9IjMuMTQxNTkyNyIKICAgICAgIGlua3NjYXBlOmZsYXRzaWRlZD0idHJ1ZSIKICAgICAgIGlua3NjYXBlOnJvdW5kZWQ9IjAiCiAgICAgICBpbmtzY2FwZTpyYW5kb21pemVkPSIwIgogICAgICAgZD0ibSAxMS43ODM3NDQsMzQuNzg1OTgzIDAsLTM1LjM5MDE0OTYzIDMwLjY0ODc2OCwxNy42OTUwNzQ2MyB6IgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSItNi42Njg0MTU5IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4zMDU0NTI5LDAsMCwxLjEzMDA0NzYsLTMuMjAyMzc3OCwxMi42ODY0NTkpIiAvPgogIDwvZz4KPC9zdmc+Cg==
"""
-dock_left_b64=\
-"""
+dock_left_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB3aWR0aD0iNjRweCIKICAgaGVpZ2h0PSI2NHB4IgogICBpZD0ic3ZnMjk4NSIKICAgdmVyc2lvbj0iMS4xIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ4LjQgcjk5MzkiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImRvY2stbGVmdC5zdmciPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMyOTg3IiAvPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI1LjA5NjgzMTIiCiAgICAgaW5rc2NhcGU6Y3g9Ii01OS45NzI4ODUiCiAgICAgaW5rc2NhcGU6Y3k9IjE2LjE5MzQxMyIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjI1NjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTM2MSIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTkiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii05IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOnNuYXAtbm9kZXM9ImZhbHNlIj4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDI5ODciCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhMjk5MCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGUgLz4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlt5b3Jpa3ZhbmhhdnJlXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6dGl0bGU+QXJjaF9TZWN0aW9uUGxhbmVfVHJlZTwvZGM6dGl0bGU+CiAgICAgICAgPGRjOmRhdGU+MjAxMS0xMi0wNjwvZGM6ZGF0ZT4KICAgICAgICA8ZGM6cmVsYXRpb24+aHR0cDovL3d3dy5mcmVlY2Fkd2ViLm9yZy93aWtpL2luZGV4LnBocD90aXRsZT1BcnR3b3JrPC9kYzpyZWxhdGlvbj4KICAgICAgICA8ZGM6cHVibGlzaGVyPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRDwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cHVibGlzaGVyPgogICAgICAgIDxkYzppZGVudGlmaWVyPkZyZWVDQUQvc3JjL01vZC9BcmNoL1Jlc291cmNlcy9pY29ucy9BcmNoX1NlY3Rpb25QbGFuZV9UcmVlLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8Y2M6bGljZW5zZT5odHRwczovL3d3dy5nbnUub3JnL2NvcHlsZWZ0L2xlc3Nlci5odG1sPC9jYzpsaWNlbnNlPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPHBhdGgKICAgICAgIHNvZGlwb2RpOnR5cGU9InN0YXIiCiAgICAgICBzdHlsZT0iY29sb3I6IzAwMDAwMDtmaWxsOiM4MDgwODA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOiM0ZDRkNGQ7c3Ryb2tlLXdpZHRoOjEuNTc0ODgyMjcwMDAwMDAwMDA7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiCiAgICAgICBpZD0icGF0aDI5OTciCiAgICAgICBzb2RpcG9kaTpzaWRlcz0iMyIKICAgICAgIHNvZGlwb2RpOmN4PSIyMiIKICAgICAgIHNvZGlwb2RpOmN5PSIxNy4wOTA5MDgiCiAgICAgICBzb2RpcG9kaTpyMT0iMjAuNDMyNTEyIgogICAgICAgc29kaXBvZGk6cjI9IjEwLjIxNjI1NyIKICAgICAgIHNvZGlwb2RpOmFyZzE9IjIuMDk0Mzk1MSIKICAgICAgIHNvZGlwb2RpOmFyZzI9IjMuMTQxNTkyNyIKICAgICAgIGlua3NjYXBlOmZsYXRzaWRlZD0idHJ1ZSIKICAgICAgIGlua3NjYXBlOnJvdW5kZWQ9IjAiCiAgICAgICBpbmtzY2FwZTpyYW5kb21pemVkPSIwIgogICAgICAgZD0ibSAxMS43ODM3NDQsMzQuNzg1OTgzIDAsLTM1LjM5MDE0OTYzIDMwLjY0ODc2OCwxNy42OTUwNzQ2MyB6IgogICAgICAgaW5rc2NhcGU6dHJhbnNmb3JtLWNlbnRlci14PSI2LjY2ODQxNTkiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgtMS4zMDU0NTI5LDAsMCwxLjEzMDA0NzYsNjcuNTc0MzkxLDEyLjY4NjQ1OSkiIC8+CiAgPC9nPgo8L3N2Zz4K
"""
-stop_grey_b64=\
-"""
+stop_grey_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjQ4LjAwMDAwMHB4IgogICBoZWlnaHQ9IjQ4LjAwMDAwMHB4IgogICBpZD0ic3ZnNjM2MSIKICAgc29kaXBvZGk6dmVyc2lvbj0iMC4zMiIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMC40OC40IHI5OTM5IgogICBzb2RpcG9kaTpkb2NuYW1lPSJzdG9wLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMSI+CiAgPGRlZnMKICAgICBpZD0iZGVmczMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzNzk4Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzMzMzMzMztzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODAwIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojMzMzMzMzO3N0b3Atb3BhY2l0eTowOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4MDIiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDI0IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjQ4IDogMjQgOiAxIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjI0IDogMTYgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlNTIiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDIyNTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmYwMjAyO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDIyNTgiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZjliOWI7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMjI2MCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDIyNDgiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDIyNTAiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjA7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wMjI1MiIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDk2NDciPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDk2NDkiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNkYmRiZGI7c3RvcC1vcGFjaXR5OjE7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wOTY1MSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDc4OTUiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDc4OTciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjA7IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNzg5OSIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQ5ODEiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojY2MwMDAwO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDQ5ODMiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNiMzAwMDA7c3RvcC1vcGFjaXR5OjEuMDAwMDAwMDsiCiAgICAgICAgIG9mZnNldD0iMS4wMDAwMDAwIgogICAgICAgICBpZD0ic3RvcDQ5ODUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQxNTc2MiIKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMTU3NjQiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MTsiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMTU3NjYiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MDsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQxNDIzNiI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMTQyMzgiCiAgICAgICAgIG9mZnNldD0iMC4wMDAwMDAwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWQ0MDQwO3N0b3Atb3BhY2l0eToxLjAwMDAwMDA7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDE0MjQwIgogICAgICAgICBvZmZzZXQ9IjEuMDAwMDAwMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2E0MDAwMDtzdG9wLW9wYWNpdHk6MS4wMDAwMDAwOyIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDExNzgwIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmOGI4YjtzdG9wLW9wYWNpdHk6MS4wMDAwMDAwOyIKICAgICAgICAgb2Zmc2V0PSIwLjAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wMTE3ODIiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlYzFiMWI7c3RvcC1vcGFjaXR5OjEuMDAwMDAwMDsiCiAgICAgICAgIG9mZnNldD0iMS4wMDAwMDAwIgogICAgICAgICBpZD0ic3RvcDExNzg0IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MTEwMTQiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYTgwMDAwO3N0b3Atb3BhY2l0eToxLjAwMDAwMDA7IgogICAgICAgICBvZmZzZXQ9IjAuMDAwMDAwMCIKICAgICAgICAgaWQ9InN0b3AxMTAxNiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2M2MDAwMDtzdG9wLW9wYWNpdHk6MS4wMDAwMDAwOyIKICAgICAgICAgb2Zmc2V0PSIwLjAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wMTMyNDUiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlNTAwMDA7c3RvcC1vcGFjaXR5OjEuMDAwMDAwMDsiCiAgICAgICAgIG9mZnNldD0iMS4wMDAwMDAwIgogICAgICAgICBpZD0ic3RvcDExMDE4IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjkuNjUwNzUzMCIKICAgICAgIHgyPSI5Ljg5NDAyMjkiCiAgICAgICB5MT0iNS4zODU1NDI0IgogICAgICAgeDE9IjUuNzM2NTI3MCIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoLTEuMDAwMDAwLDAuMDAwMDAwLDAuMDAwMDAwLC0xLjAwMDAwMCwzMS43MjE3MCwzMS4yOTA3OSkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDE1NzcyIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MTU3NjIiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDc4OTUiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ3OTAxIgogICAgICAgeDE9IjE1LjU3ODg3NSIKICAgICAgIHkxPSIxNi4yODUwODgiCiAgICAgICB4Mj0iMzIuMTY2NDA1IgogICAgICAgeTI9IjI4LjM5NDI5MSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0OTgxIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MjI0MyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjIzLjk5NTk4NSIKICAgICAgIHkxPSIyMC4xMDUzMzciCiAgICAgICB4Mj0iNDEuMDQ3ODM2IgogICAgICAgeTI9IjM3Ljk1OTc4NSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45ODgzNzMsMC4wMDAwMDAsMC4wMDAwMDAsMC45ODgzNzMsMC4yNzkwMDIsMC4yNzg5ODQpIiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyMjQ4IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MzAyMiIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCg0LjE1NDk1NywwLDAsMy4xOTg3MjMsLTUyLjg0NTUzLC0xNi42MTg2OCkiCiAgICAgICBjeD0iMTYuNzUiCiAgICAgICBjeT0iMTAuNjY2MzQ0IgogICAgICAgZng9IjE2Ljc1IgogICAgICAgZnk9IjEwLjY2NjM0NCIKICAgICAgIHI9IjIxLjI1IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzNzk4IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzgwNCIKICAgICAgIHgxPSIxLjk5ODQwMDMiCiAgICAgICB5MT0iMjQiCiAgICAgICB4Mj0iNDYuMDAxNiIKICAgICAgIHkyPSIyNCIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaW5rc2NhcGU6Z3VpZGUtYmJveD0idHJ1ZSIKICAgICBzaG93Z3VpZGVzPSJ0cnVlIgogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIwLjE1Mjk0MTE4IgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSIxNiIKICAgICBpbmtzY2FwZTpjeD0iMi4zNDgwNjI2IgogICAgIGlua3NjYXBlOmN5PSI5Ljk5NjEwOSIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9ImZhbHNlIgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjEiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9Ii05IgogICAgIGlua3NjYXBlOndpbmRvdy15PSItOSIKICAgICBpbmtzY2FwZTpzaG93cGFnZXNoYWRvdz0iZmFsc2UiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIgLz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGE0Ij4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZT48L2RjOnRpdGxlPgogICAgICAgIDxkYzpkYXRlPjIwMDUtMTAtMTY8L2RjOmRhdGU+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5BbmRyZWFzIE5pbHNzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnN1YmplY3Q+CiAgICAgICAgICA8cmRmOkJhZz4KICAgICAgICAgICAgPHJkZjpsaT5zdG9wPC9yZGY6bGk+CiAgICAgICAgICAgIDxyZGY6bGk+aGFsdDwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmVycm9yPC9yZGY6bGk+CiAgICAgICAgICA8L3JkZjpCYWc+CiAgICAgICAgPC9kYzpzdWJqZWN0PgogICAgICAgIDxjYzpsaWNlbnNlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9wdWJsaWNkb21haW4vIiAvPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkpha3ViIFN0ZWluZXI8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICA8L2NjOldvcms+CiAgICAgIDxjYzpMaWNlbnNlCiAgICAgICAgIHJkZjphYm91dD0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvcHVibGljZG9tYWluLyI+CiAgICAgICAgPGNjOnBlcm1pdHMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zI1JlcHJvZHVjdGlvbiIgLz4KICAgICAgICA8Y2M6cGVybWl0cwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjRGlzdHJpYnV0aW9uIiAvPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyNEZXJpdmF0aXZlV29ya3MiIC8+CiAgICAgIDwvY2M6TGljZW5zZT4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaWQ9ImxheWVyMSIKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIj4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzgwNCk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiMzMzMzMzM7c3Ryb2tlLXdpZHRoOjE7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgIGQ9Ik0gMTUuNTk1MDIxLDIuNDk3NDk2MiBIIDMyLjY4MDMyNiBMIDQ1LjUwMTYsMTUuNTkxOTYgViAzMy40ODU2MDUgTCAzMi44NTMwMDEsNDUuNTAyNTA0IEggMTUuNDIyNjY0IEwgMi40OTg0MDAzLDMyLjY2MzgzOSBWIDE1LjQ2OTY1MyB6IgogICAgICAgaWQ9InBhdGg5NDgwIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJvcGFjaXR5OjAuODEzMTg2ODMwMDAwMDAwMDM7ZmlsbDojMzMzMzMzO3N0cm9rZTojMWExYTFhO3N0cm9rZS13aWR0aDoxLjAwMDAwMDI0MDAwMDAwMDEwO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gMTYuMDE3ODg3LDMuNTA2MjU2MiBIIDMyLjI0NTc5NSBMIDQ0LjQ5MzY4OCwxNS45Mjg2MzEgViAzMy4wNDI5MTUgTCAzMi42MzU3MDQsNDQuNDkzNzQ0IEggMTUuODY3NDg1IEwgMy41MDYzMTE2LDMyLjIxNDYzMiBWIDE1Ljg1MTUyNCB6IgogICAgICAgaWQ9InBhdGg5NDgyIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjY2MiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJvcGFjaXR5OjAuMjg5NzcyNzI7ZmlsbDp1cmwoI3JhZGlhbEdyYWRpZW50MzAyMik7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmUiCiAgICAgICBkPSJNIDE1LjY4NzUsNy42NDA1MzAzIDIuNzUsMjAuNDUzMDMgdiAxNyBsIDIuOTM3NSwyLjkwNjI1IEMgMjIuNDUwMDQxLDQwLjQxNjgyOSAyMi4xNjQ2NjUsMjcuMzQwNTk3IDQ1LjI1LDI4LjQ4NDI4IFYgMjAuNTc4MDMgTCAzMi41NjI1LDcuNjQwNTMwMyB6IgogICAgICAgaWQ9InBhdGgyMjQxIgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjYyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgPC9nPgo8L3N2Zz4K
"""
-stop_b64=\
-"""
+stop_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjQ4LjAwMDAwMHB4IgogICBoZWlnaHQ9IjQ4LjAwMDAwMHB4IgogICBpZD0ic3ZnNjM2MSIKICAgc29kaXBvZGk6dmVyc2lvbj0iMC4zMiIKICAgaW5rc2NhcGU6dmVyc2lvbj0iMC45Mi4xIHIxNTM3MSIKICAgc29kaXBvZGk6ZG9jbmFtZT0ic3RvcC5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIgogICB2ZXJzaW9uPSIxLjEiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMzIj4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAyNCA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI0OCA6IDI0IDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIyNCA6IDE2IDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTUyIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyMjU2Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmMDIwMjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AyMjU4IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmY5YjliO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDIyNjAiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQyMjQ4Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AyMjUwIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eTowOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDIyNTIiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ5NjQ3Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A5NjQ5IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZGJkYmRiO3N0b3Atb3BhY2l0eToxOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDk2NTEiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ3ODk1Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A3ODk3IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eTowOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDc4OTkiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0OTgxIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2NjMDAwMDtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3A0OTgzIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYjMwMDAwO3N0b3Atb3BhY2l0eToxLjAwMDAwMDA7IgogICAgICAgICBvZmZzZXQ9IjEuMDAwMDAwMCIKICAgICAgICAgaWQ9InN0b3A0OTg1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MTU3NjIiCiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDE1NzY0IgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDE1NzY2IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmZmZmY7c3RvcC1vcGFjaXR5OjA7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MTQyMzYiPgogICAgICA8c3RvcAogICAgICAgICBpZD0ic3RvcDE0MjM4IgogICAgICAgICBvZmZzZXQ9IjAuMDAwMDAwMCIKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2VkNDA0MDtzdG9wLW9wYWNpdHk6MS4wMDAwMDAwOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AxNDI0MCIKICAgICAgICAgb2Zmc2V0PSIxLjAwMDAwMDAiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEuMDAwMDAwMDsiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQxMTc4MCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZjhiOGI7c3RvcC1vcGFjaXR5OjEuMDAwMDAwMDsiCiAgICAgICAgIG9mZnNldD0iMC4wMDAwMDAwIgogICAgICAgICBpZD0ic3RvcDExNzgyIiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWMxYjFiO3N0b3Atb3BhY2l0eToxLjAwMDAwMDA7IgogICAgICAgICBvZmZzZXQ9IjEuMDAwMDAwMCIKICAgICAgICAgaWQ9InN0b3AxMTc4NCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDExMDE0Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2E4MDAwMDtzdG9wLW9wYWNpdHk6MS4wMDAwMDAwOyIKICAgICAgICAgb2Zmc2V0PSIwLjAwMDAwMDAiCiAgICAgICAgIGlkPSJzdG9wMTEwMTYiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNjNjAwMDA7c3RvcC1vcGFjaXR5OjEuMDAwMDAwMDsiCiAgICAgICAgIG9mZnNldD0iMC4wMDAwMDAwIgogICAgICAgICBpZD0ic3RvcDEzMjQ1IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZTUwMDAwO3N0b3Atb3BhY2l0eToxLjAwMDAwMDA7IgogICAgICAgICBvZmZzZXQ9IjEuMDAwMDAwMCIKICAgICAgICAgaWQ9InN0b3AxMTAxOCIgLz4KICAgIDwvbGluZWFyR3JhZGllbnQ+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIHkyPSI5LjY1MDc1MzAiCiAgICAgICB4Mj0iOS44OTQwMjI5IgogICAgICAgeTE9IjUuMzg1NTQyNCIKICAgICAgIHgxPSI1LjczNjUyNzAiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KC0xLjAwMDAwMCwwLjAwMDAwMCwwLjAwMDAwMCwtMS4wMDAwMDAsMzEuNzIxNzAsMzEuMjkwNzkpIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQxNTc3MiIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDE1NzYyIgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQxMTc4MCIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDIwNTciCiAgICAgICB4MT0iMTUuNzM3MDAxIgogICAgICAgeTE9IjEyLjUwMzYwMCIKICAgICAgIHgyPSI1My41NzAxMjYiCiAgICAgICB5Mj0iNDcuMzc0MzE3IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKC0wLjAwMjc2NzYsMC4wMDU5MTM4KSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDk4MSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQ5ODciCiAgICAgICB4MT0iMjMuOTk1OTg1IgogICAgICAgeTE9IjIwLjEwNTMzNyIKICAgICAgIHgyPSI0MS4wNDc4MzYiCiAgICAgICB5Mj0iMzcuOTU5Nzg1IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0idHJhbnNsYXRlKDAuMDA0MDE0NjUsMC4wMDU1NzQ4NSkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDc4OTUiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ3OTAxIgogICAgICAgeDE9IjE1LjU3ODg3NSIKICAgICAgIHkxPSIxNi4yODUwODgiCiAgICAgICB4Mj0iMzIuMTY2NDA1IgogICAgICAgeTI9IjI4LjM5NDI5MSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQ0OTgxIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MjI0MyIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgeDE9IjIzLjk5NTk4NSIKICAgICAgIHkxPSIyMC4xMDUzMzciCiAgICAgICB4Mj0iNDEuMDQ3ODM2IgogICAgICAgeTI9IjM3Ljk1OTc4NSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC45ODgzNzMsMC4wMDAwMDAsMC4wMDAwMDAsMC45ODgzNzMsMC4yNzkwMDIsMC4yNzg5ODQpIiAvPgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQyMjQ4IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MjI1NCIKICAgICAgIGN4PSIxNi43NSIKICAgICAgIGN5PSIxMC42NjYzNDQiCiAgICAgICBmeD0iMTYuNzUiCiAgICAgICBmeT0iMTAuNjY2MzQ0IgogICAgICAgcj0iMjEuMjUiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDQuMTU0OTU3LDAsMCwzLjE5ODcyMywtNTIuODQ1NTMsLTE2LjYxODY4KSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIiAvPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaW5rc2NhcGU6Z3VpZGUtYmJveD0idHJ1ZSIKICAgICBzaG93Z3VpZGVzPSJ0cnVlIgogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIwLjE1Mjk0MTE4IgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI0IgogICAgIGlua3NjYXBlOmN4PSItMzEuNDkyNzI0IgogICAgIGlua3NjYXBlOmN5PSI3LjA1NDQ1NzYiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJmYWxzZSIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTkyMCIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMDE3IgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6c2hvd3BhZ2VzaGFkb3c9ImZhbHNlIgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiIC8+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhNCI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGUgLz4KICAgICAgICA8ZGM6ZGF0ZT4yMDA1LTEwLTE2PC9kYzpkYXRlPgogICAgICAgIDxkYzpjcmVhdG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+QW5kcmVhcyBOaWxzc29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjcmVhdG9yPgogICAgICAgIDxkYzpzdWJqZWN0PgogICAgICAgICAgPHJkZjpCYWc+CiAgICAgICAgICAgIDxyZGY6bGk+c3RvcDwvcmRmOmxpPgogICAgICAgICAgICA8cmRmOmxpPmhhbHQ8L3JkZjpsaT4KICAgICAgICAgICAgPHJkZjpsaT5lcnJvcjwvcmRmOmxpPgogICAgICAgICAgPC9yZGY6QmFnPgogICAgICAgIDwvZGM6c3ViamVjdD4KICAgICAgICA8Y2M6bGljZW5zZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvcHVibGljZG9tYWluLyIgLz4KICAgICAgICA8ZGM6Y29udHJpYnV0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5KYWt1YiBTdGVpbmVyPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgICA8Y2M6TGljZW5zZQogICAgICAgICByZGY6YWJvdXQ9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL3B1YmxpY2RvbWFpbi8iPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyNSZXByb2R1Y3Rpb24iIC8+CiAgICAgICAgPGNjOnBlcm1pdHMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zI0Rpc3RyaWJ1dGlvbiIgLz4KICAgICAgICA8Y2M6cGVybWl0cwogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjRGVyaXZhdGl2ZVdvcmtzIiAvPgogICAgICA8L2NjOkxpY2Vuc2U+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8ZwogICAgICAgaWQ9Imc1MyI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjIgogICAgICAgICBpZD0icGF0aDk0ODAiCiAgICAgICAgIGQ9Ik0gMTUuNTk1MDIxLDIuNDk3NDk2MiBIIDMyLjY4MDMyNiBMIDQ1LjUwMTYsMTUuNTkxOTYgViAzMy40ODU2MDUgTCAzMi44NTMwMDEsNDUuNTAyNTA0IEggMTUuNDIyNjY0IEwgMi40OTg0MDAzLDMyLjY2MzgzOSBWIDE1LjQ2OTY1MyBaIgogICAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50NDk4Nyk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOiM4NjAwMDA7c3Ryb2tlLXdpZHRoOjE7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgICAgPHBhdGgKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NjY2MiCiAgICAgICAgIGlkPSJwYXRoOTQ4MiIKICAgICAgICAgZD0iTSAxNi4wMTc4ODcsMy41MDYyNTYyIEggMzIuMjQ1Nzk1IEwgNDQuNDkzNjg4LDE1LjkyODYzMSBWIDMzLjA0MjkxNSBMIDMyLjYzNTcwNCw0NC40OTM3NDQgSCAxNS44Njc0ODUgTCAzLjUwNjMxMTYsMzIuMjE0NjMyIFYgMTUuODUxNTI0IFoiCiAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjAuODEzMTg2ODM7ZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZTp1cmwoI2xpbmVhckdyYWRpZW50MjA1Nyk7c3Ryb2tlLXdpZHRoOjEuMDAwMDAwMjQ7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8cGF0aAogICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIgogICAgICAgICBpZD0icGF0aDIyNDEiCiAgICAgICAgIGQ9Ik0gMTUuNjg3NSw3LjY0MDUzMDMgMi43NSwyMC40NTMwMyB2IDE3IGwgMi45Mzc1LDIuOTA2MjUgQyAyMi40NTAwNDEsNDAuNDE2ODI5IDIyLjE2NDY2NSwyNy4zNDA1OTcgNDUuMjUsMjguNDg0MjggViAyMC41NzgwMyBMIDMyLjU2MjUsNy42NDA1MzAzIFoiCiAgICAgICAgIHN0eWxlPSJvcGFjaXR5OjAuMjg5NzcyNzI7ZmlsbDp1cmwoI3JhZGlhbEdyYWRpZW50MjI1NCk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjE7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=
"""
-ok_b64=\
-"""
+ok_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI5ODAiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMSByMTUzNzEiCiAgIHNvZGlwb2RpOmRvY25hbWU9Im9rLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMSI+CiAgPGRlZnMKICAgICBpZD0iZGVmczI5ODIiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODA1Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzRlOWEwNjtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4MDciIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiM4YWUyMzQ7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODA5IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50Mzg2NCI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzg2NiIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNzFiMmY4O3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzODY4IgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiMwMDI3OTU7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg2NCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM4NTAiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC42MDI4NDU5LDEuMDQ3MTYzOSwtMS45Nzk0MDIxLDEuMTM5NTI5NSwxMjcuOTU4OCwtNzQuNDU2OTA3KSIKICAgICAgIGN4PSI1MS4zMjg4OTIiCiAgICAgICBjeT0iMzEuMDc0MTQ2IgogICAgICAgZng9IjUxLjMyODg5MiIKICAgICAgIGZ5PSIzMS4wNzQxNDYiCiAgICAgICByPSIxOS41NzE0MjgiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iNjQgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzIgOiAyMS4zMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjk4OCIgLz4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50Mzg2NCIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDMwNzYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC41ODAxOTQyMSwxLjAwNzgxNzEsLTEuOTA1MDI2OSwxLjA5NjcxMjEsNTkuMjg2NTEyLC0xOTcuODE3NDcpIgogICAgICAgY3g9IjUxLjMyODg5MiIKICAgICAgIGN5PSIzMS4wNzQxNDYiCiAgICAgICBmeD0iNTEuMzI4ODkyIgogICAgICAgZnk9IjMxLjA3NDE0NiIKICAgICAgIHI9IjE5LjU3MTQyOCIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzgwNSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MTEiCiAgICAgICB4MT0iNDkuMDU4ODIzIgogICAgICAgeTE9IjYwLjgyMzUyOCIKICAgICAgIHgyPSIzNC45NDExNzciCiAgICAgICB5Mj0iMjMuMTc2NDciCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJtYXRyaXgoMC44NSwwLDAsMC44NSw2Ni4zLDYuMzAwMDAwMSkiIC8+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI1Ljc3MDYwMzEiCiAgICAgaW5rc2NhcGU6Y3g9Ii0xMy44NjMyNjQiCiAgICAgaW5rc2NhcGU6Y3k9IjIyLjAzNzA4NSIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAxNyIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii04IgogICAgIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiCiAgICAgaW5rc2NhcGU6c25hcC1nbG9iYWw9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1iYm94PSJ0cnVlIj4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDI5OTEiCiAgICAgICBlbXBzcGFjaW5nPSIyIgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiCiAgICAgICBzbmFwdmlzaWJsZWdyaWRsaW5lc29ubHk9InRydWUiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhMjk4NSI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGUgLz4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPltZb3JpayB2YW4gSGF2cmVdPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjcmVhdG9yPgogICAgICAgIDxkYzp0aXRsZT5BcmNoX0NoZWNrPC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDEyLTA3LTIyPC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL0FyY2gvUmVzb3VyY2VzL2ljb25zL0FyY2hfQ2hlY2suc3ZnPC9kYzppZGVudGlmaWVyPgogICAgICAgIDxkYzpyaWdodHM+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEIExHUEwyKzwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cmlnaHRzPgogICAgICAgIDxjYzpsaWNlbnNlPmh0dHBzOi8vd3d3LmdudS5vcmcvY29weWxlZnQvbGVzc2VyLmh0bWw8L2NjOmxpY2Vuc2U+CiAgICAgICAgPGRjOmNvbnRyaWJ1dG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2Fncnlzb25dIEFsZXhhbmRlciBHcnlzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8ZwogICAgICAgaWQ9ImczNzA4IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS40MTAxNTYyLDAsMCwxLjQxMDE1NjIsLTExMS44MzU5NCwtMjcuMjI2NTYyKSI+CiAgICAgIDxjaXJjbGUKICAgICAgICAgcj0iMTkiCiAgICAgICAgIGN5PSI0MiIKICAgICAgICAgY3g9IjEwMiIKICAgICAgICAgaWQ9InBhdGgzNzg1IgogICAgICAgICBzdHlsZT0iZmlsbDojNzNkMjE2O2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMTcyYTA0O3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnNxdWFyZTtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MC42MDAwMDAwMjtzdHJva2Utb3BhY2l0eToxIiAvPgogICAgICA8Y2lyY2xlCiAgICAgICAgIHI9IjE3IgogICAgICAgICBjeT0iNDIiCiAgICAgICAgIGN4PSIxMDIiCiAgICAgICAgIGlkPSJwYXRoMzc4NS0zIgogICAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzgxMSk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiM4YWUyMzQ7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6c3F1YXJlO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowLjYwMDAwMDAyO3N0cm9rZS1vcGFjaXR5OjEiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjYyIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgzODEzIgogICAgICAgICBkPSJtIDkxLDQ1IDQsLTQgNCw0IDEyLC0xMiA0LDQgLTE2LDE2IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7c3Ryb2tlOiMxNzJhMDQ7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW9wYWNpdHk6MSIgLz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=
"""
-add_block_b64=\
-"""
+add_block_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI4MjEiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMSByMTUzNzEiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImFkZC1ibG9jay15LnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiCiAgIHZlcnNpb249IjEuMSI+CiAgPGRlZnMKICAgICBpZD0iZGVmczI4MjMiPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODAxIj4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2M0YTAwMDtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBpZD0ic3RvcDM4MDMiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmY2U5NGY7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODA1IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzM3NyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM3MDEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN4PSI4NC44ODMzMjQiCiAgICAgICBjeT0iNzcuMDQyODQ3IgogICAgICAgZng9Ijg0Ljg4MzMyNCIKICAgICAgIGZ5PSI3Ny4wNDI4NDciCiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDIuODQ5MjQyMSwxLjI1ODUxMTksLTAuNDA0MDQxNSwwLjkxNDc0MDcsLTEyNS44NDEzMSwtMTAwLjI1ODA1KSIgLz4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzM3NyI+CiAgICAgIDxzdG9wCiAgICAgICAgIGlkPSJzdG9wMzM3OSIKICAgICAgICAgb2Zmc2V0PSIwIgogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmFmZjJiO3N0b3Atb3BhY2l0eToxOyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgaWQ9InN0b3AzMzgxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmZmFhMDA7c3RvcC1vcGFjaXR5OjE7IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxyYWRpYWxHcmFkaWVudAogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50MzM3NyIKICAgICAgIGlkPSJyYWRpYWxHcmFkaWVudDM2OTkiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIGN4PSI3Ni4zODMzMzEiCiAgICAgICBjeT0iOTQuMzY5NTY4IgogICAgICAgZng9Ijc2LjM4MzMzMSIKICAgICAgIGZ5PSI5NC4zNjk1NjgiCiAgICAgICByPSIxOS40Njc0MzYiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDAuOTgxODk0MywwLjE4OTQyOTUsLTAuNDEwOTQyNywyLjEzMDA5MjQsNDAuMTYzNDUzLC0xMjEuMTE1NTkpIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjY0IDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjMyIDogMjEuMzMzMzMzIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI4MjkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4MDEiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODA3IgogICAgICAgeDE9IjExMCIKICAgICAgIHkxPSIzNSIKICAgICAgIHgyPSI4NSIKICAgICAgIHkyPSIzNSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgc3ByZWFkTWV0aG9kPSJyZWZsZWN0IgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09InRyYW5zbGF0ZSgtNjIsMCkiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM4MDEtNSIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MDctNyIKICAgICAgIHgxPSIxMTAiCiAgICAgICB5MT0iMzUiCiAgICAgICB4Mj0iODUiCiAgICAgICB5Mj0iMzUiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHNwcmVhZE1ldGhvZD0icmVmbGVjdCIKICAgICAgIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTYyLC0xNikiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MDEtNSI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNjNGEwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODAzLTMiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNmY2U5NGY7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODA1LTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHBhdHRlcm4KICAgICAgIHk9IjAiCiAgICAgICB4PSIwIgogICAgICAgaGVpZ2h0PSI2IgogICAgICAgd2lkdGg9IjYiCiAgICAgICBwYXR0ZXJuVW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9IkVNRmhiYXNlcGF0dGVybiIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjMuNjA0MDAzOSIKICAgICBpbmtzY2FwZTpjeD0iLTczLjg3OTM5OSIKICAgICBpbmtzY2FwZTpjeT0iMjYuMDE4MDQyIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIKICAgICBzaG93Z3JpZD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTkyMCIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMDE3IgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTgiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQyOTkyIgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTI4MjYiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6dGl0bGU+PC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDExLTEwLTEwPC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL1BhcnQvR3VpL1Jlc291cmNlcy9pY29ucy9QYXJ0X0N5bGluZGVyLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8Y2M6bGljZW5zZT5odHRwczovL3d3dy5nbnUub3JnL2NvcHlsZWZ0L2xlc3Nlci5odG1sPC9jYzpsaWNlbnNlPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOiNmY2U5NGY7c3Ryb2tlOiMzMDJiMDA7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQuNTtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNob2Zmc2V0OjIwLjQiCiAgICAgICBkPSJtIDU1LjAwMDAwMSw1MyBjIDAsNC40MTgyNzggLTEwLjc0NTE2Niw4IC0yNCw4IEMgMTcuNzQ1MTY4LDYxIDcuMDAwMDAyLDU3LjQxODI3OCA3LjAwMDAwMiw1MyBMIDcsMTEgNTQuOTk5OTk5LDExIHoiCiAgICAgICBpZD0icGF0aDI5OTQtMyIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9InNzY2NjcyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzgwNyk7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOiNmY2U5NGY7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQuNTtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNob2Zmc2V0OjIwLjQiCiAgICAgICBkPSJNIDUzLDUxLjcyNzI3MyBDIDUzLDU1Ljc0Mzg4OSA0My4xNTAyNyw1OSAzMSw1OSAxOC44NDk3MzYsNTkgOS4wMDAwMDEsNTUuNzQzODg5IDkuMDAwMDAxLDUxLjcyNzI3MyBsIC0yZS02LC0zOCA0NC4wMDAwMDEsMCB6IgogICAgICAgaWQ9InBhdGgyOTk0LTMtNiIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9InNzY2NjcyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZmNlOTRmO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0LjU7c3Ryb2tlLW9wYWNpdHk6MTtzdHJva2UtZGFzaG9mZnNldDoyMC40IgogICAgICAgZD0iTSA1MywxNS43MjcyNzMgQyA1MSwxOSA0My4xNTAyNywyMSAzMSwyMSAxOC44NDk3MzYsMjEgMTIsMTkgOS4wMDAwMDEsMTUuNzI3MjczIgogICAgICAgaWQ9InBhdGgyOTk0LTMtNi05IgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY3NjIiAvPgogICAgPHBhdGgKICAgICAgIHNvZGlwb2RpOnR5cGU9ImFyYyIKICAgICAgIHN0eWxlPSJmaWxsOiNmY2U5NGY7c3Ryb2tlOiMzMDJiMDA7c3Ryb2tlLXdpZHRoOjEuNzU7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQuNTtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDoyMC40IgogICAgICAgaWQ9InBhdGgyOTk0IgogICAgICAgc29kaXBvZGk6Y3g9Ii0zNSIKICAgICAgIHNvZGlwb2RpOmN5PSIyNSIKICAgICAgIHNvZGlwb2RpOnJ4PSIyMSIKICAgICAgIHNvZGlwb2RpOnJ5PSI3IgogICAgICAgZD0ibSAtMTQsMjUgYSAyMSw3IDAgMSAxIC00MiwwIDIxLDcgMCAxIDEgNDIsMCB6IgogICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoMS4xNDI4NTcxLDAsMCwxLjE0Mjg1NzEsNzEsLTE3LjU3MTQyOCkiIC8+CiAgICA8cGF0aAogICAgICAgaWQ9InBhdGgyOSIKICAgICAgIGQ9Ik0gNDAuOTYwMTExLDcuMDQwMTExIFYgMzcuMDM5ODg5IgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzJlMzQzNjtzdHJva2Utd2lkdGg6Ny45OTk5NDA4N3B4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBpZD0icGF0aDMxIgogICAgICAgZD0iTSA1NiwyMiBIIDI2LjAwMDIyMiIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMyZTM0MzY7c3Ryb2tlLXdpZHRoOjcuOTk5OTQwODdweDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgaWQ9InBhdGgzMyIKICAgICAgIGQ9Ik0gNDAuOTYwMTExLDcuMDQwMTExIFYgMzcuMDM5ODg5IgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2QzZDdjZjtzdHJva2Utd2lkdGg6My45OTk5NzA0NHB4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBpZD0icGF0aDM1IgogICAgICAgZD0iTSA1NiwyMiBIIDI2LjAwMDIyMiIKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNkM2Q3Y2Y7c3Ryb2tlLXdpZHRoOjMuOTk5OTcwNDRweDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICA8cGF0aAogICAgICAgaWQ9InBhdGgzNyIKICAgICAgIGQ9Ik0gNTYsMjEuMDQwMDA3IEggMjYuMDAwMjIyIgogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6I2ZmZmZmZjtzdHJva2Utd2lkdGg6MS45OTk5ODUyMnB4O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgIDxwYXRoCiAgICAgICBpZD0icGF0aDM5IgogICAgICAgZD0iTSA0MC4wMDAxMTgsNy4wNDAxMTEgViAzNy4wMzk4ODkiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojZmZmZmZmO3N0cm9rZS13aWR0aDoxLjk5OTk4NTIycHg7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogIDwvZz4KPC9zdmc+Cg==
"""
-minimize_b64=\
-"""
+minimize_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczpzb2RpcG9kaT0iaHR0cDovL3NvZGlwb2RpLnNvdXJjZWZvcmdlLm5ldC9EVEQvc29kaXBvZGktMC5kdGQiCiAgIHhtbG5zOmlua3NjYXBlPSJodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy9uYW1lc3BhY2VzL2lua3NjYXBlIgogICB3aWR0aD0iNjRweCIKICAgaGVpZ2h0PSI2NHB4IgogICBpZD0ic3ZnMjk4NSIKICAgdmVyc2lvbj0iMS4xIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ4LjQgcjk5MzkiCiAgIHNvZGlwb2RpOmRvY25hbWU9Im1pbmltaXplLnN2ZyI+CiAgPGRlZnMKICAgICBpZD0iZGVmczI5ODciIC8+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjUuMDk2ODMxMiIKICAgICBpbmtzY2FwZTpjeD0iLTU5Ljk3Mjg4NSIKICAgICBpbmtzY2FwZTpjeT0iMTYuMTkzNDEzIgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImxheWVyMSIKICAgICBzaG93Z3JpZD0idHJ1ZSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMjU2MCIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMzYxIgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOSIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTkiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6c25hcC1ub2Rlcz0iZmFsc2UiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIHR5cGU9Inh5Z3JpZCIKICAgICAgIGlkPSJncmlkMjk4NyIKICAgICAgIGVtcHNwYWNpbmc9IjIiCiAgICAgICB2aXNpYmxlPSJ0cnVlIgogICAgICAgZW5hYmxlZD0idHJ1ZSIKICAgICAgIHNuYXB2aXNpYmxlZ3JpZGxpbmVzb25seT0idHJ1ZSIgLz4KICA8L3NvZGlwb2RpOm5hbWVkdmlldz4KICA8bWV0YWRhdGEKICAgICBpZD0ibWV0YWRhdGEyOTkwIj4KICAgIDxyZGY6UkRGPgogICAgICA8Y2M6V29yawogICAgICAgICByZGY6YWJvdXQ9IiI+CiAgICAgICAgPGRjOmZvcm1hdD5pbWFnZS9zdmcreG1sPC9kYzpmb3JtYXQ+CiAgICAgICAgPGRjOnR5cGUKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9wdXJsLm9yZy9kYy9kY21pdHlwZS9TdGlsbEltYWdlIiAvPgogICAgICAgIDxkYzp0aXRsZSAvPgogICAgICAgIDxkYzpjcmVhdG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W3lvcmlrdmFuaGF2cmVdPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjcmVhdG9yPgogICAgICAgIDxkYzp0aXRsZT5BcmNoX1NlY3Rpb25QbGFuZV9UcmVlPC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDExLTEyLTA2PC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL0FyY2gvUmVzb3VyY2VzL2ljb25zL0FyY2hfU2VjdGlvblBsYW5lX1RyZWUuc3ZnPC9kYzppZGVudGlmaWVyPgogICAgICAgIDxkYzpyaWdodHM+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEIExHUEwyKzwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6cmlnaHRzPgogICAgICAgIDxjYzpsaWNlbnNlPmh0dHBzOi8vd3d3LmdudS5vcmcvY29weWxlZnQvbGVzc2VyLmh0bWw8L2NjOmxpY2Vuc2U+CiAgICAgICAgPGRjOmNvbnRyaWJ1dG9yPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+W2Fncnlzb25dIEFsZXhhbmRlciBHcnlzb248L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNvbnRyaWJ1dG9yPgogICAgICA8L2NjOldvcms+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciI+CiAgICA8cGF0aAogICAgICAgc29kaXBvZGk6dHlwZT0ic3RhciIKICAgICAgIHN0eWxlPSJjb2xvcjojMDAwMDAwO2ZpbGw6Izk5OTk5OTtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6IzRkNGQ0ZDtzdHJva2Utd2lkdGg6MS41NzQ4ODIyNztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1kYXNob2Zmc2V0OjA7bWFya2VyOm5vbmU7dmlzaWJpbGl0eTp2aXNpYmxlO2Rpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIKICAgICAgIGlkPSJwYXRoMjk5NyIKICAgICAgIHNvZGlwb2RpOnNpZGVzPSIzIgogICAgICAgc29kaXBvZGk6Y3g9IjIyIgogICAgICAgc29kaXBvZGk6Y3k9IjE3LjA5MDkwOCIKICAgICAgIHNvZGlwb2RpOnIxPSIyMC40MzI1MTIiCiAgICAgICBzb2RpcG9kaTpyMj0iMTAuMjE2MjU3IgogICAgICAgc29kaXBvZGk6YXJnMT0iMi4wOTQzOTUxIgogICAgICAgc29kaXBvZGk6YXJnMj0iMy4xNDE1OTI3IgogICAgICAgaW5rc2NhcGU6ZmxhdHNpZGVkPSJ0cnVlIgogICAgICAgaW5rc2NhcGU6cm91bmRlZD0iMCIKICAgICAgIGlua3NjYXBlOnJhbmRvbWl6ZWQ9IjAiCiAgICAgICBkPSJtIDExLjc4Mzc0NCwzNC43ODU5ODMgMCwtMzUuMzkwMTQ5NjMgMzAuNjQ4NzY4LDE3LjY5NTA3NDYzIHoiCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLDAuNTk3OTI3MDMsMS4xNDcyNDA3LDAsMTIuMzkyNjE0LDIxLjYwNjM2NCkiCiAgICAgICBpbmtzY2FwZTp0cmFuc2Zvcm0tY2VudGVyLXk9IjMuMDU0Mjg1NyIgLz4KICA8L2c+Cjwvc3ZnPgo=
"""
-export3DStep_b64=\
-"""
+export3DStep_b64 = """
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOxAAADsQBlSsOGwAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAAPdEVYdEF1dGhvcgBbd21heWVyXauF7RsAAAAYdEVYdENyZWF0aW9uIFRpbWUAMjAxMS0xMC0xMEUb11UAAA6XSURBVHic7Zt5cF3Vfcc/59x7375I8pNsSV7kBSNb8oqNCSRmSWywCdCUEsjANEydzLSdTlvaP9KmbdImbZJ2piGdtlAIIQ1pQ6GUgoEJNCm7iV0Wy3gR2LIsL9re0/b25S6nf9ynDSNrsRx5Jv7O3LnvvHuW3/me3++c37nnd+ESfrUhZrOypiY8XkGjo2gGFipFPYJ6AbXA/HJ7leXsw/fBMXcF9AJdStElBJ3AGSk4JLy0vvsu5mzKC+dJwLp11GOyHcH1AtYBqwBjdkQ7CybQquAAilekzUv7P6TrfCudNgFr17JU2uxCcBvuSI9ASsGi+iCXLY9QNz9AdbWf6iof1TEfVZVepCYIB11+ImH3nkq7g5rOmji2YmCwSDyRp2+wSDyepzue49jxFKc7sziO+qjwBxXsxuaRlg/ouKAErG9mm1D8sYJtgAQIBnSuWB9jyxU1rFldybKGMD6vNhM5JkWhaNPekebgkUH2vRvnnf195PLW8GNHwf9Ih7/f38rPp1PvpARsuJw6ZfA9FHcAeD0a266v47M3LmZ9cxW6Lqffm1mAZTm0HBrg+ZdO8bNXuiiWbPeB4klhc99UzeOcBGxYxVYleRaoCAR0dt2zks/d3DCivhcLUmmTp5/v4NF/P0ouZwEMOorb3j/CG5OVnZCAdY2sFBpvA5Gtn1jAn9y3jpqYbxbFnn30JvJ85/73eWNvD0BSwqb3DtN2rjITGmxtDQ8g2HjjDQv5ztc3EQpeXKP+cQgFDbZfX0/HqQztHWmfAzW9Cf7rXGUmNGAh+HWAP/jtJqScVXfhgkJKwR/+ThMAAn5j0vwTPVCgAyilJspy0WKMyPpkeSedwr/34OGz1t+LGY6j+O4/H5xy/kkZ+tmrneQLFn963zrmV/vPS7gLjZ54nm/df4C39vVOucyExr2+CQUQDXtIpksE/Dr33n0Zt3+2gWjEMwvizh6GkiWefqGDH/7bUfIFe0RmgJbD517qJyXgxf+8kfsfPMxLL58BwOORfGZrHbfsWML6NVUYc+QImZZDy8EBnvvpSX7+ehelkgPATZ9eyH2/28yNt78IzAIB77x8GwBvv9fHY4+3sm//AI7bFn6f5rrCm2pobqxg+dIIAf+kVjUj5PKW6wq3DrL3nTjvtfSRL7jenxCwcbWf3/riGrZsqgVg0w3PApMTMGVpN2+IsXnjp+jqyvDU7jbe3JfgxKkcb+7t5c29rs1JKaivDXDZ8ih18/3U1PiJVfmoifmoqvQhNQgHDYQQhEMGQozfDFmmw8BgkUR/gb6BAvFEgc6uLMfaU3R2Z8fO7ggB9dWCLetD3Hn7KpavrJ0GnWPqmejBRzWg93QHVdULMHzD3qAiEc/yi7d7eLtlgOMnMpw4lcW0nBkJMhl0DepqNJbUedjQHOaaLfU0LK9FM1wHzTItek60sXBlI3ABNMAsFkl0ncEbCBKKRPH4/VTXhLj15hXcenM5j2XTcTJDe0eKeL87gom+PPG+AkPJIpapyOQslFO+KwgFXWc0FNCQEioiOlUVBlUVBrEqDwtq/CxfGmHZskqCoQBSjnde8+kU8c7TDPb2AGqEgKli2gZrFgukBkw0Xcfj9+Px+tB1A6lpGLrGZcujXLY8Ot1qp4xiIUculSY92MdATw/FfA6paWiahtSmvxWf8YyllMIsFrEtC03TXSEMA03X0aQGUri6p5RrS8OaqBh9BigUylblOh0c28KxbSzLwrJKmPkCpUKeQj5HPpPGLBZxbBvbtnFse6bij2BWp2zlODi2jQCk0FAwTtjhyy53cjRd/u3YIwRMVGa2MTeL+EWESwTMtQBzjUsEzLUAc41LBMy1AHONSwTMtQBzjUsEzLUAc41LBMy1AHONX3kCZrwdth1FfKhEV79Fd8KkZAuyeQclBFIINE1jXqVBZUgnGtKpjRnMi1yY2IHzwbQJ+OBkga9/v5OT3SVMe3onRlVRg8aGII1LfKxq8HPl6iDR4NyeO06bgKdfHaTtTHFGjQ0kTd46MMRbB9y0lLC6wc81a0N8ojlA4+Jf/gn0tAkIeEenjcu3RqltDhCq1DECGoZHInV3RJUDhYxNfsgkEzfp7Shw+r0spfzoWx3HgUPteQ6153noGVhUY7DzqhA7tvioCk9PMxwH5AwsbNoEVEVHizTvrKRhfcXUCysoFWxS8SJdR3K0PNdPoj0/8vh03OSh3YM88jxsutzLrVf7uapxchH/4Tl47ZDF3dfB+mun05sZEFBdMVokMzjNsD0BHr9GbEmA2JIAa3fEKOZtej7I8t6zCdr3pgGwHdjXWmRfa5El8zXuvNbHtWvkxy5Z77TBKwfduegnr1nc256mcVl4yiJNm4DYWAISowTks0UyyTwI99RGSonU3NVA0zV0XaIbOlIbr9pev8aSDRGWbIhQyFq07Rliz496yfS7dZ/stfm7J7M8+qLk9mt0dlwhGK7CsuFfXx6tz3bga/90mCe/e9WFI2DeGBNI9pRGfluWTWooixACId2lUEgxkhZCIAXoHg3DY+D1G3i8Bpo2Oq6+oE7z9hhN2+aROFHg1YfPcLolC0BfyuGhn5Z4+i3BPdcKPtUEL7wj6BocT+ie/f288Hr3hSNgrAkMdY+uBpqU2JbjdtYROFIgHcYR4EiBU1CYJZt8toiUAsOj4w948Aa8I6E4Qghqlvm549srSPYUef3Rbo69kQQgkVTcv1vxzF7oTY52fuuuOl7/gRsZ980HW1HK1cRZJyAc0PAYkpLpMNQ5agKaLrFtG+GMjroa7rwzelfjCAHbdigVTUQyh8/vwR/w4vEZI0RU1Pq45c+Wkukv8sYj3bS+MgTAifioTJvvrGHzHTX0tuX48LUhTvfkCQlJmMnPKWfkCldXuutNts9Clc/KdY9OtDJEpCJIpDJIKOzHG/BgeHSEENiWjW3ZWLZ7t20b23KwbQfLcrBNh1ymyEAiTV9Pkny2OBLsI4DwPC87v9LArh82smhtaEQWwyu5+p4FAHzm9xaOjHpWySl0f4aucCxq0Bk3UQ6UijZev0TTJHUNsQnLOI7CLFmYRYtisUQxb1EqmuAohBAoyYimOI6DWbLIJDWCYR/+oBdRNo+KWh+f/9sV9BzPsudH3Wy5az664Y6jL6yz9ct1vPZwFwpIogHnPk2aMQHDKGQtvP7JPTgpBV6fgddnEMKNNVJKUSyY5LIFCpkiZskeN3E6jsIazJJO5QmG/QTDPneEBSxYEeT2b6w4q52Nt1Xzf0/EySctCkqwoFm/rueQ9epEcs2MgDET4dtP9RCt82D4JLrHHSVNl3iDGt6gjjco8Yc9+ILjZ3xwbdzn9+DzeyAGpmmRTxdJp3JYpl3WDIFjO6QGM+TSecIVAfwBr2sXYyY5VU5KTXDzVxfz1Ffa3f8d7gc2MYEqzIiAsSvBgWeSUyojdKha5KGuOcCi5iDVK/xU1PjRjVH/1TB0jCqdSFWQfK5IZihPLltwNcJxNWIgkcbjyROpDOD1l4O1lCKTyhOKBhDA4rURalcF6G7NAayvWW18OX7E/JePlWsigT8aIRLvPIVVLCE1jZajBb707XbON4ZSSFi6OcTqbRUsWhMhED07+sy2bVKDOdKDORRqnJ/hC3iIVAYpFiyy6TzRqhC+sjkO9RT4wb0fDFfTZwjr8jOHGZgOAf1A1WvP7SQYNLAtk/6ebhzbRtM0jnWWON1rIqSkZELJFggpkVKSzloUSor+ZIlEf5Ge/gInOnMMpc7tOseW+djyhRjLr6zE+Mh3B7blMNSfJp109w5yhAjcCVIIdEOjurYCUV4K/veB07Ts7i/XoP6x94j9+1MmYF0Tjwu466YbFvLXf36FW4VSZFNJCpmM23g5KmM4QGI0PRqtMfasf3CowLHTWQ4eTfH+0QzvH0tzqrd0VttSFzTfVMHGz1VTVR8YJ6Rl2gwm0qTTeSSMTpplQqIVQcKVAQBKeZsHP38Iy1QAFkpu6G0tHRrb1oQbyPoaDij4YtuJlO/Y8SSfvKoWjyHx+Hz4Q2GkLlGOAhRSSsSYazg9TNrw5TUEC6oM1qwI8OnNUb6wPcbOq6PUxwws26G338JR7la692iBlt39dH2YZv5KP4GIq9pSkwTDPoJhP8W8iVlyY41Uua1S0SQQ9iGlRDMk4WqNtl+kASRCNWYTzmNTIqA7wcCCGt4Afq3jVMb/H//dzrx5PlYsDaNpEt3w4PUH8Pj8SE1zO0/Z55+AgNHLGfkdCUialvnYeVWYWz4ZIuwXdPeZpPPuBJPsMmnZ3U//mSyL1wcxPO4ErOmSoYEMZtF0w2yUQilwlMKxHIJhN5ptXkOAI68MUszYAEuDNeJQNqFaJyUAoCfB6foYP1aCOsty1ry+p4fHnmgjn7NYsjhCMKiX3//p6LqBbrjBUlJKEKLslQl3iSpPmO5oOSjHJUGUF3YpJeGgzuamCHfvmM+qpUFOdBboT7rfBfV3lFi1PUIw4gUgPZQj0T0EqlzniBaAWbLwBz3u7lMKFjR6OfSi+3WegCsrverhVAqrnJ4a1jZxg4Q/AnZQdqEDfo1bblrC9uvrWdYQJhQ0prQBmSr+5uEPeODx4wCs2Bri1q+uGBHYsRWO45TN8OyeSCnR9FEtfOYvj9O+L+OmBV+LH7a++THFJseGVSxxJLsE3AqsHVuHlIKmxgqu3jKflcsiVMd8VES9RMIGXq+GEKBJd8SHiXKXUoXtuCpcLDikMiUOtyX50l/tx7IUQsKuxy4nGpt5tHp6oMj373Z3iQjy0rFWdbdy8rzGa3MTCyzBNqW4AffDySZgVkLJB5VGocztxjsq+NRvLkIztPP60nPPTzrZ+1jCTQjxRO9h865ZfSd93XXoA700apJmJViIoh5FHYJ6oBrX84zimtDwy8QhXDc1BVhAvICwBpV23WzK9jFQjmDrRfkxUE2T/hdC8Y1fQlPfujCx7ecJx7Ee0YR+BYKF58yo0EFN/Q3ouLJiQNPlj/8fNekbya6hBWUAAAAASUVORK5CYII=
"""
-pcb_edge_b64=\
-"""
+pcb_edge_b64 = """
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjY0cHgiCiAgIGhlaWdodD0iNjRweCIKICAgaWQ9InN2ZzI4MjUiCiAgIHNvZGlwb2RpOnZlcnNpb249IjAuMzIiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTEgcjEzNzI1IgogICBzb2RpcG9kaTpkb2NuYW1lPSJTa2V0Y2hlcl9SZWN0YW5nbGUuc3ZnIgogICBpbmtzY2FwZTpvdXRwdXRfZXh0ZW5zaW9uPSJvcmcuaW5rc2NhcGUub3V0cHV0LnN2Zy5pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzMjgyNyI+CiAgICA8cmFkaWFsR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDMxNDQiCiAgICAgICBpZD0icmFkaWFsR3JhZGllbnQyMjI5IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDAuNjk4NTI5NCwwLDIwMi44Mjg2MykiCiAgICAgICBjeD0iMjI1LjI2NDAyIgogICAgICAgY3k9IjY3Mi43OTczNiIKICAgICAgIGZ4PSIyMjUuMjY0MDIiCiAgICAgICBmeT0iNjcyLjc5NzM2IgogICAgICAgcj0iMzQuMzQ1MTg4IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzMTQ0Ij4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2ZmZmZmZjtzdG9wLW9wYWNpdHk6MTsiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzMTQ2IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZmZmZmZmO3N0b3Atb3BhY2l0eTowOyIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDMxNDgiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPHJhZGlhbEdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzMTQ0IgogICAgICAgaWQ9InJhZGlhbEdyYWRpZW50MjIxNSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLDAsMCwwLjY5ODUyOTQsMCwyMDIuODI4NjMpIgogICAgICAgY3g9IjIyNS4yNjQwMiIKICAgICAgIGN5PSI2NzIuNzk3MzYiCiAgICAgICBmeD0iMjI1LjI2NDAyIgogICAgICAgZnk9IjY3Mi43OTczNiIKICAgICAgIHI9IjM0LjM0NTE4OCIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUyODMzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODM2LTAiCiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODAxLTEiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSItMTgiCiAgICAgICB5MT0iMTgiCiAgICAgICB4Mj0iLTIyIgogICAgICAgeTI9IjUiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MzYtMCI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODM4LTIiIC8+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNlZjI5Mjk7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMSIKICAgICAgICAgaWQ9InN0b3AzODQwLTUiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzODM2LTAtNiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDM4MDEtMS0zIgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iLTE4IgogICAgICAgeTE9IjE4IgogICAgICAgeDI9Ii0yMiIKICAgICAgIHkyPSI1IiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQzODM2LTAtNiI+CiAgICAgIDxzdG9wCiAgICAgICAgIHN0eWxlPSJzdG9wLWNvbG9yOiNhNDAwMDA7c3RvcC1vcGFjaXR5OjEiCiAgICAgICAgIG9mZnNldD0iMCIKICAgICAgICAgaWQ9InN0b3AzODM4LTItNyIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6I2VmMjkyOTtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM4NDAtNS01IiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgeTI9IjYwIgogICAgICAgeDI9IjEyLjAwMDAwMSIKICAgICAgIHkxPSI0OCIKICAgICAgIHgxPSIxNi4wMDAwMDIiCiAgICAgICBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEuMTEwMDAyNiwwLDAsLTEuNjQ4NTIyNyw3Mi45MTk3OTksMTAxLjQ0ODQ2KSIKICAgICAgIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzA0OS05IgogICAgICAgeGxpbms6aHJlZj0iI2xpbmVhckdyYWRpZW50NDA4MS01IgogICAgICAgaW5rc2NhcGU6Y29sbGVjdD0iYWx3YXlzIiAvPgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpZD0ibGluZWFyR3JhZGllbnQ0MDgxLTUiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojZWYyOTI5O3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wNDA4My02IiAvPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojYTQwMDAwO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjEiCiAgICAgICAgIGlkPSJzdG9wNDA4NS0yIiAvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjkuOTUzMTI1IgogICAgIGlua3NjYXBlOmN4PSIzMiIKICAgICBpbmtzY2FwZTpjeT0iMzIiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzM1MjciCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE2MDAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODI4IgogICAgIGlua3NjYXBlOndpbmRvdy14PSItOSIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iLTkiCiAgICAgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgaWQ9ImdyaWQyOTk3IgogICAgICAgZW1wc3BhY2luZz0iMiIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIgogICAgICAgc25hcHZpc2libGVncmlkbGluZXNvbmx5PSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTI4MzAiPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgICAgPGRjOmNyZWF0b3I+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5bd21heWVyXTwvZGM6dGl0bGU+CiAgICAgICAgICA8L2NjOkFnZW50PgogICAgICAgIDwvZGM6Y3JlYXRvcj4KICAgICAgICA8ZGM6dGl0bGU+U2tldGNoZXJfQ3JlYXRlUmVjdGFuZ2xlPC9kYzp0aXRsZT4KICAgICAgICA8ZGM6ZGF0ZT4yMDExLTEwLTEwPC9kYzpkYXRlPgogICAgICAgIDxkYzpyZWxhdGlvbj5odHRwOi8vd3d3LmZyZWVjYWR3ZWIub3JnL3dpa2kvaW5kZXgucGhwP3RpdGxlPUFydHdvcms8L2RjOnJlbGF0aW9uPgogICAgICAgIDxkYzpwdWJsaXNoZXI+CiAgICAgICAgICA8Y2M6QWdlbnQ+CiAgICAgICAgICAgIDxkYzp0aXRsZT5GcmVlQ0FEPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpwdWJsaXNoZXI+CiAgICAgICAgPGRjOmlkZW50aWZpZXI+RnJlZUNBRC9zcmMvTW9kL1NrZXRjaGVyL0d1aS9SZXNvdXJjZXMvaWNvbnMvU2tldGNoZXJfQ3JlYXRlUmVjdGFuZ2xlLnN2ZzwvZGM6aWRlbnRpZmllcj4KICAgICAgICA8ZGM6cmlnaHRzPgogICAgICAgICAgPGNjOkFnZW50PgogICAgICAgICAgICA8ZGM6dGl0bGU+RnJlZUNBRCBMR1BMMis8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgICA8Y2M6bGljZW5zZT5odHRwczovL3d3dy5nbnUub3JnL2NvcHlsZWZ0L2xlc3Nlci5odG1sPC9jYzpsaWNlbnNlPgogICAgICAgIDxkYzpjb250cmlidXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPlthZ3J5c29uXSBBbGV4YW5kZXIgR3J5c29uPC9kYzp0aXRsZT4KICAgICAgICAgIDwvY2M6QWdlbnQ+CiAgICAgICAgPC9kYzpjb250cmlidXRvcj4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpZD0ibGF5ZXIxIgogICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgIGlua3NjYXBlOmdyb3VwbW9kZT0ibGF5ZXIiPgogICAgPGcKICAgICAgIGlua3NjYXBlOmV4cG9ydC15ZHBpPSI2LjU4OTU2NjciCiAgICAgICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNi41ODk1NjY3IgogICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL3JlY3RhbmdsZS5wbmciCiAgICAgICBpZD0iZzM1MjciCiAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjEzNjc3MDIsMCwwLDAuMTM2NzcwMiwtMTI1Ljg0Njc0LC00Ny45NjIwOTIpIj4KICAgICAgPGcKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXlkcGk9IjYuNTg5NTY2NyIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LXhkcGk9IjYuNTg5NTY2NyIKICAgICAgICAgaW5rc2NhcGU6ZXhwb3J0LWZpbGVuYW1lPSIvaG9tZS95b3Jpay9Eb2N1bWVudHMvTGFiL0RyYWZ0L2ljb25zL3JlY3RhbmdsZS5wbmciCiAgICAgICAgIGlkPSJnMzUyNy0zIgogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCgwLjkyMDAwMDA0LDAsMCwwLjk5ODUyODI2LDkyLjMyODA4LDEuMTA3OTMzNSkiPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgaWQ9InJlY3QyMjMzIgogICAgICAgICAgIGQ9Im0gOTcxLjMxMzQ5LDQxNS45ODQ1NyAwLDMzNi44MjYyOSAzNjUuNTc2NzEsMCAwLC0zMzYuODI2MjkgeiBtIDQzLjg2OTIxLDQ0LjM2NDkyIDI3NC4wMjM2LC0wLjQzMTA1IDAsMjQ4Ljk1ODU3IC0yNzQuMDIzNiwwLjA2NDYgeiIKICAgICAgICAgICBzdHlsZT0iZmlsbDojZDNkN2NmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMmUzNDM2O3N0cm9rZS13aWR0aDoxNS4yNTY4MzQwMztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjYyIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgICBkPSJtIDU1LjkxMzA0NSwxMC45MzUxNDkgLTQ2LjczOTEyODYsMCAwLDQzLjA2MzM3OCIKICAgICAgICAgICBpZD0icGF0aDMwNDAiCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCg3LjMxMTUzNDIsMCwwLDcuMzExNTM0Miw5MjAuMTMyNzUsMzUwLjY3NjQ4KSIKICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjYyIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiNmZmZmZmY7c3Ryb2tlLXdpZHRoOjIuMDg2NjgwMTc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOnJvdW5kO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICAgICAgZD0ibSAxMyw1MSAzOS42ODU1NzUsMC4wMzIxOSAtMC4wNjk4NywtMzYuMTI4NzU1IgogICAgICAgICAgIGlkPSJwYXRoMzA0MiIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDcuMzExNTM0MiwwLDAsNy4zMTE1MzQyLDkyMC4xMzI3NSwzNTAuNjc2NDgpIgogICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjIiAvPgogICAgICA8L2c+CiAgICAgIDxnCiAgICAgICAgIHRyYW5zZm9ybT0ibWF0cml4KDcuMzExNTM0MiwwLDAsNy4zMTE1MzQyLDEyMTIuNjM2MSw1OC4xNzUyOTkpIgogICAgICAgICBpZD0iZzM4MjctMSI+CiAgICAgICAgPGcKICAgICAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzMS4zMjIxMzEsNDAuNTcwMjg5KSIKICAgICAgICAgICBpZD0iZzM3OTctOSI+CiAgICAgICAgICA8cGF0aAogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMyODAwMDA7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODgwMDAwMDAwMDY7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2Utb3BhY2l0eToxO3N0cm9rZS1kYXNoYXJyYXk6bm9uZSIKICAgICAgICAgICAgIGlkPSJwYXRoNDI1MC03MSIKICAgICAgICAgICAgIGQ9Ik0gLTI2LjE1NjIwNCw1LjU4MjYyNiBBIDguOTkzODE4LDguOTkzNDA3NyAwLjAyMDQyMjgzIDEgMSAtMTIuNDkzNzkzLDE3LjI4MjI0MSA4Ljk5MzgxOCw4Ljk5MzQwNzcgMC4wMjA0MjI4MyAxIDEgLTI2LjE1NjIwNCw1LjU4MjYyNiB6IiAvPgogICAgICAgICAgPHBhdGgKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDp1cmwoI2xpbmVhckdyYWRpZW50MzgwMS0xKTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2VmMjkyOTtzdHJva2Utd2lkdGg6MS45OTk5OTk1MjAwMDAwMDAwMztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICAgICAgaWQ9InBhdGg0MjUwLTctMyIKICAgICAgICAgICAgIGQ9Ik0gLTI0LjYzMzU4OCw2Ljg5MzU4OCBBIDYuOTk5OTk5Nyw3LjAwMDAwMDEgMCAxIDEgLTE0LDE2IDYuOTk5OTk5Nyw3LjAwMDAwMDEgMCAwIDEgLTI0LjYzMzU4OCw2Ljg5MzU4OCB6IiAvPgogICAgICAgIDwvZz4KICAgICAgPC9nPgogICAgICA8ZwogICAgICAgICB0cmFuc2Zvcm09Im1hdHJpeCg3LjMxMTUzNDIsMCwwLDcuMzExNTM0Miw5MjAuMTMyNzUsMzUwLjY3NjQ4KSIKICAgICAgICAgaWQ9ImczODI3LTEtMyI+CiAgICAgICAgPGcKICAgICAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgzMS4zMjIxMzEsNDAuNTcwMjg5KSIKICAgICAgICAgICBpZD0iZzM3OTctOS01Ij4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzI4MDAwMDtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODAwMDAwMDAwNjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICAgICAgaWQ9InBhdGg0MjUwLTcxLTYiCiAgICAgICAgICAgICBkPSJNIC0yNi4xNTYyMDQsNS41ODI2MjYgQSA4Ljk5MzgxOCw4Ljk5MzQwNzcgMC4wMjA0MjI4MyAxIDEgLTEyLjQ5Mzc5MywxNy4yODIyNDEgOC45OTM4MTgsOC45OTM0MDc3IDAuMDIwNDIyODMgMSAxIC0yNi4xNTYyMDQsNS41ODI2MjYgeiIgLz4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDM4MDEtMS0zKTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6I2VmMjkyOTtzdHJva2Utd2lkdGg6MS45OTk5OTk1MjAwMDAwMDAwMztzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1vcGFjaXR5OjE7c3Ryb2tlLWRhc2hhcnJheTpub25lIgogICAgICAgICAgICAgaWQ9InBhdGg0MjUwLTctMy0yIgogICAgICAgICAgICAgZD0iTSAtMjQuNjMzNTg4LDYuODkzNTg4IEEgNi45OTk5OTk3LDcuMDAwMDAwMSAwIDEgMSAtMTQsMTYgNi45OTk5OTk3LDcuMDAwMDAwMSAwIDAgMSAtMjQuNjMzNTg4LDYuODkzNTg4IHoiIC8+CiAgICAgICAgPC9nPgogICAgICA8L2c+CiAgICAgIDxnCiAgICAgICAgIGlkPSJnNTA4MiIKICAgICAgICAgdHJhbnNmb3JtPSJtYXRyaXgoNy4wNzM2Njc5LDAsMCw5LjEyMTMxODEsNjM4LjYxMDMxLDUzOC45ODMwNCkiPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDMwNDktOSk7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjIuMjAwMDAwMDU7bWFya2VyOm5vbmU7ZW5hYmxlLWJhY2tncm91bmQ6YWNjdW11bGF0ZSIKICAgICAgICAgICBkPSJtIDkwLjY3OTg0MiwyLjUzNzA5NyAxMy4zMjAwMjgsMTMuMTg4MTgxIC0xMy4zMjAwMjgsMTMuMTg4MTgyIDAsLTYuNTk0MDkxIC0xMy4zMjAwMzIsMCAwLC0xMy4xODgxODEgMTMuMzIwMDMyLDAgeiIKICAgICAgICAgICBpZD0icmVjdDMxNjUiCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIiAvPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO2ZpbGw6bm9uZTtzdHJva2U6I2VmMjkyOTtzdHJva2Utd2lkdGg6Mi43MDU0NDk1ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGQ9Im0gOTIuODk5ODQ4LDguNzI5MzAzNyAwLDMuMjk3MDQ1MyAtMTMuMzIwMDMzLDAgMTBlLTcsOS44OTExMzQiCiAgICAgICAgICAgaWQ9InBhdGg0MDg3IgogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjIiAvPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO2ZpbGw6bm9uZTtzdHJva2U6I2VmMjkyOTtzdHJva2Utd2lkdGg6Mi43MDU0NDk1ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGQ9Ik0gOTEuMTgxMzIxLDYuNDA4MDY2OSAxMDIuMzMxOCwxNy40OTgxMjgiCiAgICAgICAgICAgaWQ9InBhdGg0MDg5IgogICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgICAgICA8cGF0aAogICAgICAgICAgIHN0eWxlPSJkaXNwbGF5OmlubGluZTtmaWxsOm5vbmU7c3Ryb2tlOiNlZjI5Mjk7c3Ryb2tlLXdpZHRoOjEuMzUyNzI0NzlweDtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICAgIGQ9Ik0gOTAuNjc5ODQyLDEyLjQyODIzMyA5Mi44OTk4NDgsOS4xMzExODc1IgogICAgICAgICAgIGlkPSJwYXRoNDA5MSIKICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgICAgIDxwYXRoCiAgICAgICAgICAgc3R5bGU9ImRpc3BsYXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7dmlzaWJpbGl0eTp2aXNpYmxlO2ZpbGw6bm9uZTtzdHJva2U6IzM0MDQwNDtzdHJva2Utd2lkdGg6Mi45NzU5OTQ1OTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MDtzdHJva2Utb3BhY2l0eToxO21hcmtlcjpub25lO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiCiAgICAgICAgICAgZD0ibSA5MC42Nzk4NDMsMi41MzcwOTUxIDEzLjMyMDAzNywxMy4xODgxODE5IC0xMy4zMjAwMzcsMTMuMTg4MTgxIDAsLTYuNTk0MDkxIC0xMy4zMjAwMzIsMCAwLC0xMy4xODgxODExIDEzLjMyMDAzMiwwIHoiCiAgICAgICAgICAgaWQ9InJlY3QzMTY1LTEiCiAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2NjY2NjIiAvPgogICAgICA8L2c+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K
"""
+
###############################################
def find_name(n):
- n=n.lower()
+ n = n.lower()
return {
- 'prefix3d_1' : 1,
- 'prefix3d_2' : 2,
- 'pcb_color' : 3,
- 'bklist' : 4,
- 'bbox' : 5,
- 'placement' : 6,
- 'virt' : 7,
- 'exportfusing' : 8,
- 'min_drill_size': 9,
- 'last_pcb_path' :10,
- 'last_fp_path' :11,
- 'export_to_step':12,
- 'mat' :13,
- 'spin' :14,
- 'compound' :15,
- 'dkmode' :16,
- 'font_size' :17,
- 'exporting_mode':18,
- 'importing_mode':19,
- }.get(n, 0) # 0 is default if x not found
+ "prefix3d_1": 1,
+ "prefix3d_2": 2,
+ "pcb_color": 3,
+ "bklist": 4,
+ "bbox": 5,
+ "placement": 6,
+ "virt": 7,
+ "exportfusing": 8,
+ "min_drill_size": 9,
+ "last_pcb_path": 10,
+ "last_fp_path": 11,
+ "export_to_step": 12,
+ "mat": 13,
+ "spin": 14,
+ "compound": 15,
+ "dkmode": 16,
+ "font_size": 17,
+ "exporting_mode": 18,
+ "importing_mode": 19,
+ }.get(n, 0) # 0 is default if x not found
+
+
+# import ConfigParser
+# import configobj
-#
-
-#import ConfigParser
-#import configobj
def insert(filename, other):
if os.path.exists(filename):
- open(filename,True)
+ open(filename, True)
else:
FreeCAD.Console.PrintError("File does not exist.\n")
- reply = QtGui.QMessageBox.information(None,"info", "File does not exist.\n")
+ QtGui.QMessageBox.information(None, "info", "File does not exist.\n")
+
def reload_lib(lib):
- if (sys.version_info > (3, 0)):
- import importlib
- importlib.reload(lib)
- else:
- reload (lib)
+ import importlib
-def open(filename,insert=None):
- #reply = QtGui.QMessageBox.information(None,"info", filename)
- #onLoadBoard_cmd(filename)
+ importlib.reload(lib)
+
+
+def open(filename, insert=None):
+ # reply = QtGui.QMessageBox.information(None,"info", filename)
+ # onLoadBoard_cmd(filename)
global original_filename
ext = os.path.splitext(os.path.basename(filename))[1]
- sayw("kicad StepUp version "+str(___ver___))
- #say("tolerance on vertex = "+str(edge_tolerance))
+ sayw("kicad StepUp version " + str(___ver___))
+ # say("tolerance on vertex = "+str(edge_tolerance))
say("tolerance on vertex applied")
- if ext==".kicad_pcb":
- original_filename=filename
- onLoadBoard(filename,None,insert)
+ if ext == ".kicad_pcb":
+ original_filename = filename
+ onLoadBoard(filename, None, insert)
# zf= Timer (1.0,ZoomFitThread)
# zf.start()
- #elif ext==".emn":
+ # elif ext==".emn":
# onLoadBoard_idf(filename)
- elif ext==".kicad_mod":
+ elif ext == ".kicad_mod":
import kicadStepUptools
- reload_lib( kicadStepUptools )
+
+ reload_lib(kicadStepUptools)
KSUWidget.activateWindow()
KSUWidget.show()
KSUWidget.raise_()
import fps
+
fps.addfootprint(filename)
# onLoadFootprint(filename)
-
+
def make_unicode(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.decode('utf-8')
- return input
- else: #py2
- if type(input) != unicode:
- input = input.decode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.decode("utf-8")
+ if type(input) != unicode:
+ return input.decode("utf-8")
+ return input
+
def make_string(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.encode('utf-8')
- return input
- else: #py2
- if type(input) == unicode:
- input = input.encode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.encode("utf-8")
+ if type(input) == unicode:
+ return input.encode("utf-8")
+ return input
-def PLine(prm1,prm2):
- if hasattr(Part,"LineSegment"):
+
+def PLine(prm1, prm2):
+ if hasattr(Part, "LineSegment"):
return Part.LineSegment(prm1, prm2)
- else:
- return Part.Line(prm1, prm2)
-
-def light1(x,y,z):
- light = SoDirectionalLight()
- light.on = True
- # 40W Tungsten 2600 255, 197, 143
- #light.color = (1,197/255,143/255)
- light.color = (1,0.839,0.66667)
- light.intensity = 0.7
- light.direction = (x,y,z)
- return light
-
-def light2(x,y,z):
- light = SoDirectionalLight()
- light.on = True
- #Overcast Sky 7000 201, 226, 255
- #light.color = (201/255,226/255,1)
- light.color = (0.2509,0.6117,1)
- light.intensity = 0.5
- light.direction = (x,y,z)
- return light
-
-def simple_copy_link(obj): #simple copy with incremental placement
- if obj.ViewObject.Visibility != False:
- __shape = Part.getShape(obj,'',needSubElement=False,refine=False)
- FreeCAD.ActiveDocument.addObject('Part::Feature','LinkGroup').Shape=__shape
+ return Part.Line(prm1, prm2)
+
+
+def light1(x, y, z):
+ light = SoDirectionalLight()
+ light.on = True
+ # 40W Tungsten 2600 255, 197, 143
+ # light.color = (1,197/255,143/255)
+ light.color = (1, 0.839, 0.66667)
+ light.intensity = 0.7
+ light.direction = (x, y, z)
+ return light
+
+
+def light2(x, y, z):
+ light = SoDirectionalLight()
+ light.on = True
+ # Overcast Sky 7000 201, 226, 255
+ # light.color = (201/255,226/255,1)
+ light.color = (0.2509, 0.6117, 1)
+ light.intensity = 0.5
+ light.direction = (x, y, z)
+ return light
+
+
+def simple_copy_link(obj): # simple copy with incremental placement
+ if obj.ViewObject.Visibility:
+ __shape = Part.getShape(obj, "", needSubElement=False, refine=False)
+ FreeCAD.ActiveDocument.addObject("Part::Feature", "LinkGroup").Shape = __shape
nobj = FreeCAD.ActiveDocument.ActiveObject
nobjV = FreeCADGui.ActiveDocument.ActiveObject
- nobj.Label=obj.Label
- if obj.TypeId == 'App::Part':
+ nobj.Label = obj.Label
+ if obj.TypeId == "App::Part":
for subobj in obj.OutList:
- if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name),'ShapeColor'):
- nobjV.ShapeColor=FreeCADGui.ActiveDocument.getObject(subobj.Name).ShapeColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name),'LineColor'):
- #FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' LineColor ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).LineColor)+ '\n')
- nobjV.LineColor=FreeCADGui.ActiveDocument.getObject(subobj.Name).LineColor
- nobjV.PointColor=FreeCADGui.ActiveDocument.getObject(subobj.Name).PointColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name),'DiffuseColor'):
- #FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' DiffuseColor ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).DiffuseColor)+ '\n')
- nobjV.DiffuseColor=FreeCADGui.ActiveDocument.getObject(subobj.Name).DiffuseColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name),'Transparency'):
- #FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' Transparency ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).Transparency)+ '\n')
- nobjV.Transparency=FreeCADGui.ActiveDocument.getObject(subobj.Name).Transparency
+ if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name), "ShapeColor"):
+ nobjV.ShapeColor = FreeCADGui.ActiveDocument.getObject(subobj.Name).ShapeColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name), "LineColor"):
+ # FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' LineColor ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).LineColor)+ '\n')
+ nobjV.LineColor = FreeCADGui.ActiveDocument.getObject(subobj.Name).LineColor
+ nobjV.PointColor = FreeCADGui.ActiveDocument.getObject(subobj.Name).PointColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name), "DiffuseColor"):
+ # FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' DiffuseColor ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).DiffuseColor)+ '\n')
+ nobjV.DiffuseColor = FreeCADGui.ActiveDocument.getObject(subobj.Name).DiffuseColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(subobj.Name), "Transparency"):
+ # FreeCAD.Console.PrintMessage(subobj.Label);FreeCAD.Console.PrintMessage(' Transparency ' +str(FreeCADGui.ActiveDocument.getObject(subobj.Name).Transparency)+ '\n')
+ nobjV.Transparency = FreeCADGui.ActiveDocument.getObject(subobj.Name).Transparency
else:
- nobj.ViewObject.ShapeColor=getattr(obj.getLinkedObject(True).ViewObject,'ShapeColor',nobj.ViewObject.ShapeColor)
- nobj.ViewObject.LineColor= getattr(obj.getLinkedObject(True).ViewObject,'LineColor' ,nobj.ViewObject.LineColor)
- nobj.ViewObject.PointColor=getattr(obj.getLinkedObject(True).ViewObject,'PointColor',nobj.ViewObject.PointColor)
+ nobj.ViewObject.ShapeColor = getattr(
+ obj.getLinkedObject(True).ViewObject,
+ "ShapeColor",
+ nobj.ViewObject.ShapeColor,
+ )
+ nobj.ViewObject.LineColor = getattr(
+ obj.getLinkedObject(True).ViewObject,
+ "LineColor",
+ nobj.ViewObject.LineColor,
+ )
+ nobj.ViewObject.PointColor = getattr(
+ obj.getLinkedObject(True).ViewObject,
+ "PointColor",
+ nobj.ViewObject.PointColor,
+ )
FreeCAD.ActiveDocument.recompute()
-def simple_cpy_plc(obj,proot): #simple copy with incremental placement
-
- if '::CoordinateSystem' not in obj.TypeId and '::DocumentObjectGroup' not in obj.TypeId \
- and '::FeaturePython' not in obj.TypeId and 'GeoFeature' not in obj.TypeId and 'Origin' not in obj.TypeId and obj.ViewObject.Visibility != False:
- s=obj.Shape
- t=s.copy()
- r=s.copy()
- r.Placement=FreeCAD.Placement(proot)
- t.Placement=r.Placement.multiply(t.Placement) #incremental Placement
- FreeCAD.ActiveDocument.addObject('Part::Feature',obj.Name+"_cp").Shape=t
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj.Name),'ShapeColor'):
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj.Name),'LineColor'):
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj.Name),'PointColor'):
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj.Name),'DiffuseColor'):
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
- if hasattr(FreeCADGui.ActiveDocument.getObject(obj.Name),'Transparency'):
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
- new_label=make_string(obj.Label)+"_cp"
- FreeCAD.ActiveDocument.ActiveObject.Label=new_label
- #stop
-
-def get_node_plc(o,obj): # get node placement in App::Part
-
- child = FreeCAD.ActiveDocument.addObject("Part::Box","BoxC")
- node = FreeCAD.ActiveDocument.addObject("Part::Box","BoxN")
- child.Placement=o.Placement
- node.Placement=obj.Placement
- new_Placement=node.Placement.multiply(child.Placement)
+
+def simple_cpy_plc(obj, proot): # simple copy with incremental placement
+
+ if (
+ "::CoordinateSystem" not in obj.TypeId
+ and "::DocumentObjectGroup" not in obj.TypeId
+ and "::FeaturePython" not in obj.TypeId
+ and "GeoFeature" not in obj.TypeId
+ and "Origin" not in obj.TypeId
+ and obj.ViewObject.Visibility
+ ):
+ s = obj.Shape
+ t = s.copy()
+ r = s.copy()
+ r.Placement = FreeCAD.Placement(proot)
+ t.Placement = r.Placement.multiply(t.Placement) # incremental Placement
+ FreeCAD.ActiveDocument.addObject("Part::Feature", obj.Name + "_cp").Shape = t
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj.Name), "ShapeColor"):
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj.Name), "LineColor"):
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj.Name), "PointColor"):
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj.Name), "DiffuseColor"):
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject(
+ obj.Name,
+ ).DiffuseColor
+ if hasattr(FreeCADGui.ActiveDocument.getObject(obj.Name), "Transparency"):
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject(
+ obj.Name,
+ ).Transparency
+ new_label = make_string(obj.Label) + "_cp"
+ FreeCAD.ActiveDocument.ActiveObject.Label = new_label
+ # stop
+
+
+def get_node_plc(o, obj): # get node placement in App::Part
+
+ child = FreeCAD.ActiveDocument.addObject("Part::Box", "BoxC")
+ node = FreeCAD.ActiveDocument.addObject("Part::Box", "BoxN")
+ child.Placement = o.Placement
+ node.Placement = obj.Placement
+ new_Placement = node.Placement.multiply(child.Placement)
FreeCAD.ActiveDocument.removeObject("BoxC")
FreeCAD.ActiveDocument.removeObject("BoxN")
FreeCAD.ActiveDocument.recompute()
return new_Placement
-
-def recurse_node(obj,plcm,scl): # recursive function to make a simple copy of App::Part hierarchy
- if "App::Part" in obj.TypeId or 'Body' in obj.TypeId or 'App::LinkGroup' in obj.TypeId:
- #sayerr(obj.Label)
- if 'LinkGroup' in obj.TypeId:
- group = obj.OutList
- else:
- group = obj.Group
- #for o in obj.Group:
- #sayw(str(group))
+
+
+def recurse_node(obj, plcm, scl): # recursive function to make a simple copy of App::Part hierarchy
+ if "App::Part" in obj.TypeId or "Body" in obj.TypeId or "App::LinkGroup" in obj.TypeId:
+ # sayerr(obj.Label)
+ group = obj.OutList if "LinkGroup" in obj.TypeId else obj.Group
+ # for o in obj.Group:
+ # sayw(str(group))
for o in group:
- #sayerr(o.Name);sayw(o.TypeId)
- if "App::Part" in o.TypeId or 'Body' in o.TypeId or 'App::LinkGroup' in o.TypeId:
- #sayerr(o.Label)#+" * "+obj.Name)
- if "App::Part" in o.TypeId and o.Visibility==False: # avoiding objects in invisible Part containers
- print('avoiding objects in invisible Part containers')
- pass
+ # sayerr(o.Name);sayw(o.TypeId)
+ if "App::Part" in o.TypeId or "Body" in o.TypeId or "App::LinkGroup" in o.TypeId:
+ # sayerr(o.Label)#+" * "+obj.Name)
+ if "App::Part" in o.TypeId and not o.Visibility: # avoiding objects in invisible Part containers
+ print("avoiding objects in invisible Part containers")
else:
- new_plcm=get_node_plc(o,obj)
- recurse_node(o,new_plcm,scl)
- else:
- if "Sketcher" not in o.TypeId and "DocumentObjectGroup" not in o.TypeId:
- if FreeCADGui.ActiveDocument.getObject(o.Name).Visibility:
- if 'Compound2' in o.TypeId:
- simple_copy_link(o)
- #simple_cpy_plc(o,plcm)
- else:
- simple_cpy_plc(o,plcm)
- scl.append(FreeCAD.ActiveDocument.ActiveObject)
+ new_plcm = get_node_plc(o, obj)
+ recurse_node(o, new_plcm, scl)
+ elif "Sketcher" not in o.TypeId and "DocumentObjectGroup" not in o.TypeId:
+ if FreeCADGui.ActiveDocument.getObject(o.Name).Visibility:
+ if "Compound2" in o.TypeId:
+ simple_copy_link(o)
+ # simple_cpy_plc(o,plcm)
+ else:
+ simple_cpy_plc(o, plcm)
+ scl.append(FreeCAD.ActiveDocument.ActiveObject)
-class Ui_Dialog(object):
+
+class Ui_Dialog:
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(400, 164)
self.buttonBox = QtGui.QDialogButtonBox(Dialog)
self.buttonBox.setGeometry(QtCore.QRect(30, 110, 341, 32))
self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
- self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
+ self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel | QtGui.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox")
self.comboBox = QtGui.QComboBox(Dialog)
self.comboBox.setGeometry(QtCore.QRect(180, 40, 191, 22))
- self.comboBox.setMaxVisibleItems(33) #25
+ self.comboBox.setMaxVisibleItems(33) # 25
self.comboBox.setObjectName("comboBox")
self.label = QtGui.QLabel(Dialog)
self.label.setGeometry(QtCore.QRect(180, 20, 53, 16))
@@ -1955,12 +2038,12 @@ def setupUi(self, Dialog):
self.plainTextEdit = QtGui.QTextEdit(Dialog)
self.plainTextEdit.setEnabled(False)
self.plainTextEdit.setGeometry(QtCore.QRect(20, 40, 31, 31))
- #self.plainTextEdit.setBackgroundVisible(True)
+ # self.plainTextEdit.setBackgroundVisible(True)
self.plainTextEdit.setObjectName("plainTextEdit")
self.plainTextEdit_2 = QtGui.QTextEdit(Dialog)
self.plainTextEdit_2.setEnabled(False)
self.plainTextEdit_2.setGeometry(QtCore.QRect(120, 40, 31, 31))
- #self.plainTextEdit_2.setBackgroundVisible(True)
+ # self.plainTextEdit_2.setBackgroundVisible(True)
self.plainTextEdit_2.setObjectName("plainTextEdit_2")
self.label_3 = QtGui.QLabel(Dialog)
self.label_3.setGeometry(QtCore.QRect(120, 20, 41, 16))
@@ -1968,15 +2051,19 @@ def setupUi(self, Dialog):
self.label_4 = QtGui.QLabel(Dialog)
self.label_4.setGeometry(QtCore.QRect(20, 80, 351, 16))
self.label_4.setObjectName("label_4")
- QtCore.QObject.connect(self.comboBox, QtCore.SIGNAL("currentIndexChanged(QString)"), self.SIGNAL_comboBox_Changed)
+ QtCore.QObject.connect(
+ self.comboBox,
+ QtCore.SIGNAL("currentIndexChanged(QString)"),
+ self.SIGNAL_comboBox_Changed,
+ )
self.retranslateUi(Dialog)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), Dialog.accept)
QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), Dialog.reject)
QtCore.QMetaObject.connectSlotsByName(Dialog)
- def SIGNAL_comboBox_Changed(self,text):
- #say("combo changed "+text)
+ def SIGNAL_comboBox_Changed(self, text):
+ # say("combo changed "+text)
comboBox_Changed(text)
def retranslateUi(self, Dialog):
@@ -1987,123 +2074,157 @@ def retranslateUi(self, Dialog):
self.plainTextEdit_2.setToolTip(translate("Ui_Dialog", "Diffuse Color"))
self.label_3.setText(translate("Ui_Dialog", "New"))
self.label_4.setText(translate("Ui_Dialog", "NB: set Material will unmatch colors between wrl and STEP"))
+
+
###
def isWritable(path):
try:
- testfile = tempfile.TemporaryFile(dir = path)
- testfile.close()
- #sayw('ok')
+ with tempfile.TemporaryFile(dir=path):
+ pass
+ # sayw('ok')
return True
except:
- #except OSError as e:
- #sayw('ko')
- sayw('folder not writable!')
- pass
+ # except OSError as e:
+ # sayw('ko')
+ sayw("folder not writable!")
return False
- #if e.errno == errno.EACCES: # 13
+ # if e.errno == errno.EACCES: # 13
# return False
- #e.filename = path
- #return False
- #raise
- sayw('folder not writable!')
+ # e.filename = path
+ # return False
+ # raise
+ sayw("folder not writable!")
return False
+
+
###
def comboBox_Changed(text_combo):
global ui, shape_col
- #say(text_combo)
- material_index=material_properties_names.index(text_combo)
- #say(material_index)
- mat_prop = material_properties[material_index].split('\n')
- if len(mat_prop)>1:
+ # say(text_combo)
+ material_index = material_properties_names.index(text_combo)
+ # say(material_index)
+ mat_prop = material_properties[material_index].split("\n")
+ if len(mat_prop) > 1:
# say(mat_prop[2])
- color_rgb=mat_prop[2].split(' ')
+ color_rgb = mat_prop[2].split(" ")
# say (color_rgb)
# say(color_rgb[9]+" "+color_rgb[10]+" "+color_rgb[11])
## pal = QtGui.QPalette()
## bgc = QtGui.QColor(float(color_rgb[9])*255,float(color_rgb[10])*255, float(color_rgb[11])*255)
## pal.setColor(QtGui.QPalette.Base, bgc)
## ui.plainTextEdit_2.viewport().setPalette(pal)
- #say(material_index)
- ui.plainTextEdit_2.setStyleSheet("#plainTextEdit_2 {background-color:rgb("+str(float(color_rgb[9])*255)+","+str(float(color_rgb[10])*255)+","+str(float(color_rgb[11])*255)+");}")
+ # say(material_index)
+ ui.plainTextEdit_2.setStyleSheet(
+ "#plainTextEdit_2 {background-color:rgb("
+ + str(float(color_rgb[9]) * 255)
+ + ","
+ + str(float(color_rgb[10]) * 255)
+ + ","
+ + str(float(color_rgb[11]) * 255)
+ + ");}",
+ )
else:
- #say(str(material_index)+" here")
- #ui.plainTextEdit_2.setStyleSheet("#plainTextEdit_2 {background-color:rgb("+str(0*255)+","+str(1*255)+","+str(0*255)+");}")
- ui.plainTextEdit_2.setStyleSheet("#plainTextEdit_2 {background-color:rgb("+str(shape_col[0]*255)+","+str(shape_col[1]*255)+","+str(shape_col[2]*255)+");}")
+ # say(str(material_index)+" here")
+ # ui.plainTextEdit_2.setStyleSheet("#plainTextEdit_2 {background-color:rgb("+str(0*255)+","+str(1*255)+","+str(0*255)+");}")
+ ui.plainTextEdit_2.setStyleSheet(
+ "#plainTextEdit_2 {background-color:rgb("
+ + str(shape_col[0] * 255)
+ + ","
+ + str(shape_col[1] * 255)
+ + ","
+ + str(shape_col[2] * 255)
+ + ");}",
+ )
+
###
+
# https://forum.freecad.org/viewtopic.php?t=71391 https://github.com/easyw/kicadStepUpMod/issues/187
def shapeToMesh(shape, color, transp, mesh_deviation, scale=None):
- #mesh_deviation=0.1 #the smaller the best quality, 1 coarse
- #say(mesh_deviation)
- mesh_data = shape.tessellate(mesh_deviation, True) # forcing new mesh each time
+ # mesh_deviation=0.1 #the smaller the best quality, 1 coarse
+ # say(mesh_deviation)
+ mesh_data = shape.tessellate(mesh_deviation, True) # forcing new mesh each time
points = mesh_data[0]
if scale is not None:
- points = map(lambda p: p*scale, points)
- newMesh= Mesh(points = points,
- faces = mesh_data[1],
- color = color, transp=transp)
- return newMesh
+ points = (p * scale for p in points)
+ return Mesh(points=points, faces=mesh_data[1], color=color, transp=transp)
+
def assignSTEPmaterials(objects, filepath):
- """Export step file with material properties
- """
+ """Export step file with material properties"""
global ui, shape_col
global color_list, color_list_mat
- color_list=[]
- color_list_mat=[]
- index_color=-1
+ color_list = []
+ color_list_mat = []
+ index_color = -1
Dialog = QtGui.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
ui.comboBox.addItems(material_properties_names)
- material="as is"
+ material = "as is"
for obj in objects:
for color in obj.ViewObject.DiffuseColor:
- shape_col= color
- #say(shape_col)
+ shape_col = color
+ # say(shape_col)
if shape_col not in color_list:
- #sayw(shape_col);say('not found')
- idc=0;material_index=0
- found_mat=False
- for mat_diff_col in material_properties_diffuse:
- #say(mat_diff_col)
- delta_col=0.01
- if ((abs(shape_col[0]-mat_diff_col[0]):"/\|?*,;:\\'), None)
- exp_name=exp_name.translate(translation_table)
+
+ exp_name = componentObjs[0].Label if label is None else label
+ # removing not allowed chars
+ translation_table = dict.fromkeys(map(ord, '<>:"/\\|?*,;:\\'), None)
+ exp_name = exp_name.translate(translation_table)
path, fname = os.path.split(fullfilePathName)
- fname=os.path.splitext(fname)[0]
- save_wrz=False
+ fname = os.path.splitext(fname)[0]
+ save_wrz = False
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if prefs.GetBool('wrz_export_enabled'):
+ if prefs.GetBool("wrz_export_enabled"):
#'stpz'
- save_wrz=True
- #print('stpZ',fullFilePathNameStep)
+ save_wrz = True
+ # print('stpZ',fullFilePathNameStep)
if scale is not None:
- if save_wrz:
- filename=path+os.sep+exp_name+'.wrz'
- else:
- filename=path+os.sep+exp_name+'.wrl'
+ filename = path + os.sep + exp_name + ".wrz" if save_wrz else path + os.sep + exp_name + ".wrl"
+ elif save_wrz:
+ filename = path + os.sep + exp_name + "_1_1.wrz"
else:
- if save_wrz:
- filename=path+os.sep+exp_name+'_1_1.wrz'
- else:
- filename=path+os.sep+exp_name+'_1_1.wrl'
+ filename = path + os.sep + exp_name + "_1_1.wrl"
say(filename)
- exportV=True
- if prefs.GetBool('wrl_disable') == True:
+ exportV = True
+ if prefs.GetBool("wrl_disable"):
#'stpz'
- exportV=False
+ exportV = False
else:
- exportV=True
+ exportV = True
# if exportV == False:
# assignSTEPmaterials(objects, filepath)
# return # 'wrl export disabled'
if exportV:
- mesh_deviation_default=0.9 # 0.03 or 0.1 0.9 smaller files
- mesh_dev=mesh_deviation_default #the smaller the best quality, 1 coarse
+ mesh_deviation_default = 0.9 # 0.03 or 0.1 0.9 smaller files
+ mesh_dev = mesh_deviation_default # the smaller the best quality, 1 coarse
if os.path.exists(filename):
- say('file exists')
+ say("file exists")
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.question(None, "Info", filename+"\nwrl file exists, overwrite?",
- QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
+ reply = QtGui.QMessageBox.question(
+ None,
+ "Info",
+ filename + "\nwrl file exists, overwrite?",
+ QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
+ QtGui.QMessageBox.No,
+ )
if reply == QtGui.QMessageBox.Yes:
# this is where the code relevant to a 'Yes' answer goes
- exportV=True
- #pass
+ exportV = True
+ # pass
if reply == QtGui.QMessageBox.No:
# this is where the code relevant to a 'No' answer goes
- exportV=False
- #pass
- reply = QtGui.QInputDialog.getText(None, "Mesh Deviation","Mesh Deviation ([range:0.01-1] the smaller the better quality)",QtGui.QLineEdit.Normal,str(mesh_deviation_default))
+ exportV = False
+ # pass
+ reply = QtGui.QInputDialog.getText(
+ None,
+ "Mesh Deviation",
+ "Mesh Deviation ([range:0.01-1] the smaller the better quality)",
+ QtGui.QLineEdit.Normal,
+ str(mesh_deviation_default),
+ )
if reply[1]:
- # user clicked OK
- replyText = reply[0]
- if float (replyText) < 0.01:
- mesh_dev = 0.01
- elif float (replyText) > 1.0:
- mesh_dev = 1.0
- else:
- mesh_dev = float (replyText)
+ # user clicked OK
+ replyText = reply[0]
+ if float(replyText) < 0.01:
+ mesh_dev = 0.01
+ elif float(replyText) > 1.0:
+ mesh_dev = 1.0
+ else:
+ mesh_dev = float(replyText)
else:
- # user clicked Cancel
- replyText = reply[0] # which will be "" if they clicked Cancel
- mesh_dev=mesh_deviation_default #the smaller the best quality, 1 coarse
- #default
- creaseAngle_default=1.0
+ # user clicked Cancel
+ replyText = reply[0] # which will be "" if they clicked Cancel
+ mesh_dev = mesh_deviation_default # the smaller the best quality, 1 coarse
+ # default
+ creaseAngle_default = 1.0
creaseAngle_max = 3.14
- reply = QtGui.QInputDialog.getText(None, "creaseAngle","creaseAngle [range:0-"+str(creaseAngle_max)+"] the bigger the best quality (0->None)\ncheck your wrl result",QtGui.QLineEdit.Normal,str(creaseAngle_default))
+ reply = QtGui.QInputDialog.getText(
+ None,
+ "creaseAngle",
+ "creaseAngle [range:0-"
+ + str(creaseAngle_max)
+ + "] the bigger the best quality (0->None)\ncheck your wrl result",
+ QtGui.QLineEdit.Normal,
+ str(creaseAngle_default),
+ )
if reply[1]:
- # user clicked OK
- replyText = reply[0]
- if float (replyText) < 0.0:
- creaseAngle = 0.0
- elif float (replyText) > creaseAngle_max:
- creaseAngle = creaseAngle_max
- else:
- creaseAngle = float (replyText)
+ # user clicked OK
+ replyText = reply[0]
+ if float(replyText) < 0.0:
+ creaseAngle = 0.0
+ elif float(replyText) > creaseAngle_max:
+ creaseAngle = creaseAngle_max
+ else:
+ creaseAngle = float(replyText)
else:
- # user clicked Cancel
- replyText = reply[0] # which will be "" if they clicked Cancel
- creaseAngle=creaseAngle_default #the bigger the best quality, 1 coarse
- #default
- #say(mesh_deviation)
- say("mesh deviation: "+str(mesh_dev)) # 1 for small wrl files
- say("creaseAngle: "+str(creaseAngle)) # 0 for small wrl files
- color=[]
- Diffuse_color=[]
- transparency=[]
+ # user clicked Cancel
+ replyText = reply[0] # which will be "" if they clicked Cancel
+ creaseAngle = creaseAngle_default # the bigger the best quality, 1 coarse
+ # default
+ # say(mesh_deviation)
+ say("mesh deviation: " + str(mesh_dev)) # 1 for small wrl files
+ say("creaseAngle: " + str(creaseAngle)) # 0 for small wrl files
+ color = []
+ Diffuse_color = []
+ transparency = []
for obj in componentObjs:
- #say(obj.Label)
+ # say(obj.Label)
## if hasattr(obj,'ShapeColor'):
color.append(FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor)
- transparency.append(FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency/100.0)
- #say("color")
- #say(FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor)
+ transparency.append(FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency / 100.0)
+ # say("color")
+ # say(FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor)
Diffuse_color.append(FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor)
- i=0
- meshes=[]
- #say("diffuse color")
- #say(Diffuse_color)
- indexColor=0;
- color_vector=[]
- applyDiffuse=0
+ i = 0
+ meshes = []
+ # say("diffuse color")
+ # say(Diffuse_color)
+ indexColor = 0
+ color_vector = []
+ applyDiffuse = 0
for obj in componentObjs:
- shape1=obj.Shape
- single_color=Diffuse_color[i];
- #check length color
- #say("len color")
- #say(len(single_color))
- #colors less then faces
- if(len(single_color)!=len(shape1.Faces)):
- applyDiffuse=0;
- #copy color to all faces
- #else copy singular colors for faces
+ shape1 = obj.Shape
+ single_color = Diffuse_color[i]
+ # check length color
+ # say("len color")
+ # say(len(single_color))
+ # colors less then faces
+ if len(single_color) != len(shape1.Faces):
+ applyDiffuse = 0
+ # copy color to all faces
+ # else copy singular colors for faces
else:
- applyDiffuse=1;
- for color in single_color:
- color_vector.append(color)
- #say("color_vector")
- #say(color_vector)
+ applyDiffuse = 1
+ color_vector.extend(single_color)
+ # say("color_vector")
+ # say(color_vector)
for index in range(len(shape1.Faces)):
- #say("color x")
- #say(color_vector[indexColor])
- singleFace=shape1.Faces[index]
+ # say("color x")
+ # say(color_vector[indexColor])
+ singleFace = shape1.Faces[index]
if exportV:
- if(applyDiffuse):
- #say(color_vector[indexColor])
+ if applyDiffuse:
+ # say(color_vector[indexColor])
meshes.append(shapeToMesh(singleFace, color_vector[indexColor], transparency[i], mesh_dev, scale))
else:
- #say(single_color[0])
+ # say(single_color[0])
meshes.append(shapeToMesh(singleFace, single_color[0], transparency[i], mesh_dev, scale))
- indexColor=indexColor+1
- #meshes.append(shapeToMesh(face, Diffuse_color[i], transparency[i], scale))
- color_vector=[]
- indexColor=0;
- i=i+1
+ indexColor = indexColor + 1
+ # meshes.append(shapeToMesh(face, Diffuse_color[i], transparency[i], scale))
+ color_vector = []
+ indexColor = 0
+ i = i + 1
if enable_materials == 1 and exportV:
- # print 'ciao'
- #if applymaterials==1:
+ # print 'ciao'
+ # if applymaterials==1:
exportVRMLmaterials(meshes, filename)
elif exportV:
exportVRML(meshes, filename)
elif enable_materials == 1:
assignSTEPmaterials(componentObjs, filename)
- return
+
+
###
def check_AP():
- #say("AP")
+ # say("AP")
sel = FreeCADGui.Selection.getSelection()
- if 'App::Part' in sel[0].TypeId:
- sc_list=[]
+ if "App::Part" in sel[0].TypeId:
+ sc_list = []
sel0 = FreeCADGui.ActiveDocument.getObject(sel[0].Name)
- #sel[0].Visibility=False
+ # sel[0].Visibility=False
for obj in FreeCADGui.Selection.getSelection():
- recurse_node(obj,obj.Placement, sc_list)
- #if ('App::Part' in obj.TypeId) and (obj.Visibility==False):
+ recurse_node(obj, obj.Placement, sc_list)
+ # if ('App::Part' in obj.TypeId) and (obj.Visibility==False):
# for o in obj.OutList:
# o.Visibility=False
# if ('App::Part' in obj.TypeId): # and (obj.Visibility==True):
# recurse_node(obj,obj.Placement, sc_list)
- no_shape=True
+ no_shape = True
for ob in sc_list:
- #print(ob.Label,hasattr(ob,'Shape'))
- if hasattr(ob,'Shape'):
- no_shape=False
+ # print(ob.Label,hasattr(ob,'Shape'))
+ if hasattr(ob, "Shape"):
+ no_shape = False
if no_shape:
- msg="Select one or more objects with a Shape!"
+ msg = "Select one or more objects with a Shape!"
sayerr(msg)
say_warning(msg)
stop
- sel0.Visibility=False
- FreeCAD.activeDocument().addObject("Part::Compound",FreeCADGui.Selection.getSelection()[0].Label+"_cp")
- FreeCAD.activeDocument().ActiveObject.Links = sc_list #[FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
- mycompound=FreeCAD.activeDocument().ActiveObject
+ sel0.Visibility = False
+ FreeCAD.activeDocument().addObject("Part::Compound", FreeCADGui.Selection.getSelection()[0].Label + "_cp")
+ FreeCAD.activeDocument().ActiveObject.Links = (
+ sc_list # [FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
+ )
+ FreeCAD.activeDocument().ActiveObject
FreeCAD.activeDocument().recompute()
FreeCADGui.Selection.removeSelection(sel[0])
FreeCADGui.Selection.addSelection(FreeCAD.activeDocument().ActiveObject)
+
def simple_copy(obj):
- s=obj.Shape
- FreeCAD.ActiveDocument.addObject('Part::Feature',make_string(obj.Label)+"_cp").Shape=s
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
- new_label=make_string(obj.Label)+"_cp"
- FreeCAD.ActiveDocument.ActiveObject.Label=new_label
+ s = obj.Shape
+ FreeCAD.ActiveDocument.addObject("Part::Feature", make_string(obj.Label) + "_cp").Shape = s
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
+ new_label = make_string(obj.Label) + "_cp"
+ FreeCAD.ActiveDocument.ActiveObject.Label = new_label
FreeCAD.ActiveDocument.recompute()
+
def group_part():
- #say("gp")
+ # say("gp")
sel = FreeCADGui.Selection.getSelection()
- if len(sel)==0:
+ if len(sel) == 0:
sayw("None selected!")
- msg="Select a Compound or a Part Design group\nor more than one Part object!"
+ msg = "Select a Compound or a Part Design group\nor more than one Part object!"
sayerr(msg)
say_select_obj()
- if len(sel)==1:
- found=0
- p0 = FreeCAD.Placement (FreeCAD.Vector(0,0,0), FreeCAD.Rotation(0,0,0), FreeCAD.Vector(0,0,0))
- if 'App::Part' in sel[0].TypeId or 'Body' in sel[0].TypeId:
+ if len(sel) == 1:
+ found = 0
+ p0 = FreeCAD.Placement(FreeCAD.Vector(0, 0, 0), FreeCAD.Rotation(0, 0, 0), FreeCAD.Vector(0, 0, 0))
+ if "App::Part" in sel[0].TypeId or "Body" in sel[0].TypeId:
sayw("doing compound and single copy")
- sc_list=[]
- FreeCADGui.ActiveDocument.getObject(sel[0].Name).Visibility=False
- original_label=make_string(sel[0].Label)
- #sayerr(original_label)
- #sel[0].Visibility=False
- pOriginal=FreeCADGui.Selection.getSelection()[0].Placement
- FreeCADGui.Selection.getSelection()[0].Placement=p0
+ sc_list = []
+ FreeCADGui.ActiveDocument.getObject(sel[0].Name).Visibility = False
+ original_label = make_string(sel[0].Label)
+ # sayerr(original_label)
+ # sel[0].Visibility=False
+ pOriginal = FreeCADGui.Selection.getSelection()[0].Placement
+ FreeCADGui.Selection.getSelection()[0].Placement = p0
for obj in FreeCADGui.Selection.getSelection():
- recurse_node(obj,obj.Placement, sc_list)
- #print sc_list
- #stop
- if len (sc_list) == 1:
- #simple_copy(FreeCAD.activeDocument().getObject(sc_list[0].Name))
- #print pOriginal
- simple_cpy_plc(sc_list[0],pOriginal)
+ recurse_node(obj, obj.Placement, sc_list)
+ # print sc_list
+ # stop
+ if len(sc_list) == 1:
+ # simple_copy(FreeCAD.activeDocument().getObject(sc_list[0].Name))
+ # print pOriginal
+ simple_cpy_plc(sc_list[0], pOriginal)
FreeCAD.ActiveDocument.removeObject(sc_list[0].Name)
- FreeCAD.ActiveDocument.ActiveObject.Label=original_label+"_sc"
- found=1
- #stop
+ FreeCAD.ActiveDocument.ActiveObject.Label = original_label + "_sc"
+ found = 1
+ # stop
else:
- FreeCADGui.Selection.getSelection()[0].Placement=pOriginal
- FreeCAD.activeDocument().addObject("Part::Compound",FreeCADGui.Selection.getSelection()[0].Label+"_cp")
- FreeCAD.activeDocument().ActiveObject.Links = sc_list #[FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
- mycompound=FreeCAD.activeDocument().ActiveObject
+ FreeCADGui.Selection.getSelection()[0].Placement = pOriginal
+ FreeCAD.activeDocument().addObject(
+ "Part::Compound",
+ FreeCADGui.Selection.getSelection()[0].Label + "_cp",
+ )
+ FreeCAD.activeDocument().ActiveObject.Links = (
+ sc_list # [FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
+ )
+ mycompound = FreeCAD.activeDocument().ActiveObject
FreeCAD.activeDocument().ActiveObject.Placement = pOriginal
FreeCAD.activeDocument().recompute()
FreeCADGui.Selection.removeSelection(sel[0])
FreeCADGui.Selection.addSelection(FreeCAD.activeDocument().ActiveObject)
simple_copy(FreeCAD.activeDocument().getObject(mycompound.Name))
- FreeCADGui.ActiveDocument.getObject(mycompound.Name).Visibility=False
- FreeCAD.ActiveDocument.ActiveObject.Label=original_label+"_sp"
- FreeCAD.ActiveDocument.recompute()
- found=1
- if 'Part::Compound' in sel[0].TypeId:
+ FreeCADGui.ActiveDocument.getObject(mycompound.Name).Visibility = False
+ FreeCAD.ActiveDocument.ActiveObject.Label = original_label + "_sp"
+ FreeCAD.ActiveDocument.recompute()
+ found = 1
+ if "Part::Compound" in sel[0].TypeId:
sayw("doing single copy")
- original_label=make_string(FreeCADGui.Selection.getSelection()[0].Label)
- original_name=FreeCADGui.Selection.getSelection()[0].Name
- n_objs=0
- solids=FreeCAD.ActiveDocument.getObject(FreeCADGui.Selection.getSelection()[0].Name).Shape.Solids
+ original_label = make_string(FreeCADGui.Selection.getSelection()[0].Label)
+ original_name = FreeCADGui.Selection.getSelection()[0].Name
+ n_objs = 0
+ solids = FreeCAD.ActiveDocument.getObject(FreeCADGui.Selection.getSelection()[0].Name).Shape.Solids
for solid in solids:
solids.index(solid)
- n_objs=n_objs+1
+ n_objs = n_objs + 1
simple_copy(sel[0])
- FreeCADGui.ActiveDocument.getObject(original_name).Visibility=False
- FreeCAD.ActiveDocument.ActiveObject.Label=original_label+"_sp"
+ FreeCADGui.ActiveDocument.getObject(original_name).Visibility = False
+ FreeCAD.ActiveDocument.ActiveObject.Label = original_label + "_sp"
FreeCAD.ActiveDocument.recompute()
- found=1
+ found = 1
if "Part::MultiFuse" in sel[0].TypeId:
sayw("doing single copy")
- original_label=make_string(FreeCADGui.Selection.getSelection()[0].Label)
- original_name=FreeCADGui.Selection.getSelection()[0].Name
- n_objs=0
- solids=FreeCAD.ActiveDocument.getObject(FreeCADGui.Selection.getSelection()[0].Name).Shape.Solids
+ original_label = make_string(FreeCADGui.Selection.getSelection()[0].Label)
+ original_name = FreeCADGui.Selection.getSelection()[0].Name
+ n_objs = 0
+ solids = FreeCAD.ActiveDocument.getObject(FreeCADGui.Selection.getSelection()[0].Name).Shape.Solids
for solid in solids:
solids.index(solid)
- n_objs=n_objs+1
+ n_objs = n_objs + 1
simple_copy(sel[0])
- FreeCADGui.ActiveDocument.getObject(original_name).Visibility=False
- FreeCAD.ActiveDocument.ActiveObject.Label=original_label+"_sp"
+ FreeCADGui.ActiveDocument.getObject(original_name).Visibility = False
+ FreeCAD.ActiveDocument.ActiveObject.Label = original_label + "_sp"
FreeCAD.ActiveDocument.recompute()
- found=1
- if found==0:
+ found = 1
+ if found == 0:
say_select_obj()
- if len(sel)>1:
- objs=[]
+ if len(sel) > 1:
+ objs = []
for obj in sel:
- #say(obj.Label)
- if 'Part::' in obj.TypeId:
+ # say(obj.Label)
+ if "Part::" in obj.TypeId:
objs.append(obj)
- #say(obj.Label)
- if len(objs)>1:
+ # say(obj.Label)
+ if len(objs) > 1:
sayw("doing compound and single copy")
- CopyName = FreeCAD.activeDocument().getObject(objs[0].Name).Name
- original_label=make_string(objs[0].Label)
- FreeCAD.activeDocument().addObject("Part::Compound",original_label+"_mp")
- FreeCAD.activeDocument().ActiveObject.Links = objs #[FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
- mycompound=FreeCAD.activeDocument().ActiveObject
+ FreeCAD.activeDocument().getObject(objs[0].Name).Name
+ original_label = make_string(objs[0].Label)
+ FreeCAD.activeDocument().addObject("Part::Compound", original_label + "_mp")
+ FreeCAD.activeDocument().ActiveObject.Links = (
+ objs # [FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
+ )
+ mycompound = FreeCAD.activeDocument().ActiveObject
FreeCAD.activeDocument().recompute()
simple_copy(FreeCAD.activeDocument().getObject(mycompound.Name))
- FreeCADGui.ActiveDocument.getObject(mycompound.Name).Visibility=False
- FreeCAD.ActiveDocument.ActiveObject.Label=original_label+"_sp"
+ FreeCADGui.ActiveDocument.getObject(mycompound.Name).Visibility = False
+ FreeCAD.ActiveDocument.ActiveObject.Label = original_label + "_sp"
FreeCAD.ActiveDocument.recompute()
else:
say_select_obj()
-
+
def group_part_union():
- #say("gp union")
+ # say("gp union")
sel = FreeCADGui.Selection.getSelection()
- if len(sel)==0:
+ if len(sel) == 0:
sayw("None selected!")
- msg="Select a Compound or a Part Design group\nor more than one Part object!"
+ msg = "Select a Compound or a Part Design group\nor more than one Part object!"
sayerr(msg)
say_select_obj()
- if len(sel)==1:
- found=0
- p0 = FreeCAD.Placement (FreeCAD.Vector(0,0,0), FreeCAD.Rotation(0,0,0), FreeCAD.Vector(0,0,0))
- if 'App::Part' in sel[0].TypeId or 'Body' in sel[0].TypeId:
+ if len(sel) == 1:
+ found = 0
+ p0 = FreeCAD.Placement(FreeCAD.Vector(0, 0, 0), FreeCAD.Rotation(0, 0, 0), FreeCAD.Vector(0, 0, 0))
+ if "App::Part" in sel[0].TypeId or "Body" in sel[0].TypeId:
sayw("doing union and single copy")
- original_label=make_string(sel[0].Label)
- sc_list=[]
- FreeCADGui.ActiveDocument.getObject(sel[0].Name).Visibility=False
- #sel[0].Visibility=False
- pOriginal=FreeCADGui.Selection.getSelection()[0].Placement
- FreeCADGui.Selection.getSelection()[0].Placement=p0
+ original_label = make_string(sel[0].Label)
+ sc_list = []
+ FreeCADGui.ActiveDocument.getObject(sel[0].Name).Visibility = False
+ # sel[0].Visibility=False
+ pOriginal = FreeCADGui.Selection.getSelection()[0].Placement
+ FreeCADGui.Selection.getSelection()[0].Placement = p0
for obj in FreeCADGui.Selection.getSelection():
- recurse_node(obj,obj.Placement, sc_list)
- FreeCADGui.Selection.getSelection()[0].Placement=pOriginal
- #print sc_list
- #stop
- if len (sc_list) == 1:
- #simple_copy(FreeCAD.activeDocument().getObject(sc_list[0].Name))
- #print pOriginal
- simple_cpy_plc(sc_list[0],pOriginal)
+ recurse_node(obj, obj.Placement, sc_list)
+ FreeCADGui.Selection.getSelection()[0].Placement = pOriginal
+ # print sc_list
+ # stop
+ if len(sc_list) == 1:
+ # simple_copy(FreeCAD.activeDocument().getObject(sc_list[0].Name))
+ # print pOriginal
+ simple_cpy_plc(sc_list[0], pOriginal)
FreeCAD.ActiveDocument.removeObject(sc_list[0].Name)
- FreeCAD.ActiveDocument.ActiveObject.Label=original_label+"_sp"
- #stop
+ FreeCAD.ActiveDocument.ActiveObject.Label = original_label + "_sp"
+ # stop
else:
- FreeCAD.activeDocument().addObject("Part::Compound",FreeCADGui.Selection.getSelection()[0].Label+"_cp")
- FreeCAD.activeDocument().ActiveObject.Links = sc_list #[FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
- mycompound=FreeCAD.activeDocument().ActiveObject
+ FreeCAD.activeDocument().addObject(
+ "Part::Compound",
+ FreeCADGui.Selection.getSelection()[0].Label + "_cp",
+ )
+ FreeCAD.activeDocument().ActiveObject.Links = (
+ sc_list # [FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
+ )
+ mycompound = FreeCAD.activeDocument().ActiveObject
FreeCAD.activeDocument().ActiveObject.Placement = pOriginal
FreeCAD.activeDocument().recompute()
FreeCADGui.Selection.removeSelection(sel[0])
FreeCADGui.Selection.addSelection(FreeCAD.activeDocument().ActiveObject)
CopyName = FreeCAD.activeDocument().ActiveObject.Name
- FreeCAD.activeDocument().addObject("Part::MultiFuse",original_label+"_mp_cp")
+ FreeCAD.activeDocument().addObject("Part::MultiFuse", original_label + "_mp_cp")
FusionName = FreeCAD.activeDocument().ActiveObject.Name
- #say(FusionName)
- FreeCAD.activeDocument().getObject(FusionName).Shapes = [FreeCAD.activeDocument().getObject(CopyName),]
- FreeCADGui.activeDocument().getObject(CopyName).Visibility=False
- FreeCADGui.ActiveDocument.getObject(FusionName).ShapeColor=FreeCADGui.ActiveDocument.getObject(CopyName).ShapeColor
- FreeCADGui.ActiveDocument.getObject(FusionName).DisplayMode=FreeCADGui.ActiveDocument.getObject(CopyName).DisplayMode
- FreeCAD.ActiveDocument.getObject(FusionName).Label=original_label+"_fd"
+ # say(FusionName)
+ FreeCAD.activeDocument().getObject(FusionName).Shapes = [
+ FreeCAD.activeDocument().getObject(CopyName),
+ ]
+ FreeCADGui.activeDocument().getObject(CopyName).Visibility = False
+ FreeCADGui.ActiveDocument.getObject(FusionName).ShapeColor = FreeCADGui.ActiveDocument.getObject(
+ CopyName,
+ ).ShapeColor
+ FreeCADGui.ActiveDocument.getObject(FusionName).DisplayMode = FreeCADGui.ActiveDocument.getObject(
+ CopyName,
+ ).DisplayMode
+ FreeCAD.ActiveDocument.getObject(FusionName).Label = original_label + "_fd"
FreeCAD.ActiveDocument.recompute()
- if 'Invalid' in FreeCAD.ActiveDocument.getObject(FusionName).State:
+ if "Invalid" in FreeCAD.ActiveDocument.getObject(FusionName).State:
# fusion failed code...
sayerr("fusion failed! doing compound & single copy")
- msg="""Union of parts failed!
... doing Compound & single copy"""
+ msg = (
+ """Union of parts failed!
... doing Compound & single copy"""
+ )
say_warning(msg)
FreeCAD.ActiveDocument.removeObject(FusionName)
FreeCAD.ActiveDocument.recompute()
- #mycompound=FreeCAD.activeDocument().getObject
- #FreeCAD.activeDocument().recompute()
+ # mycompound=FreeCAD.activeDocument().getObject
+ # FreeCAD.activeDocument().recompute()
simple_copy(FreeCAD.activeDocument().getObject(mycompound.Name))
- FreeCADGui.ActiveDocument.getObject(mycompound.Name).Visibility=False
- FreeCAD.ActiveDocument.ActiveObject.Label=original_label+"_sp"
+ FreeCADGui.ActiveDocument.getObject(mycompound.Name).Visibility = False
+ FreeCAD.ActiveDocument.ActiveObject.Label = original_label + "_sp"
FreeCAD.ActiveDocument.recompute()
else:
simple_copy(FreeCAD.activeDocument().getObject(FusionName))
- FreeCADGui.ActiveDocument.getObject(FusionName).Visibility=False
- FreeCAD.ActiveDocument.ActiveObject.Label=original_label+"_sp"
+ FreeCADGui.ActiveDocument.getObject(FusionName).Visibility = False
+ FreeCAD.ActiveDocument.ActiveObject.Label = original_label + "_sp"
FreeCAD.ActiveDocument.recompute()
- found=1
- if 'Part::Compound' in sel[0].TypeId:
+ found = 1
+ if "Part::Compound" in sel[0].TypeId:
sayw("doing single copy")
- original_label=make_string(FreeCADGui.Selection.getSelection()[0].Label)
- original_name=FreeCADGui.Selection.getSelection()[0].Name
- n_objs=0
- solids=FreeCAD.ActiveDocument.getObject(FreeCADGui.Selection.getSelection()[0].Name).Shape.Solids
+ original_label = make_string(FreeCADGui.Selection.getSelection()[0].Label)
+ original_name = FreeCADGui.Selection.getSelection()[0].Name
+ n_objs = 0
+ solids = FreeCAD.ActiveDocument.getObject(FreeCADGui.Selection.getSelection()[0].Name).Shape.Solids
for solid in solids:
solids.index(solid)
- n_objs=n_objs+1
+ n_objs = n_objs + 1
simple_copy(sel[0])
- FreeCADGui.ActiveDocument.getObject(original_name).Visibility=False
- FreeCAD.ActiveDocument.ActiveObject.Label=original_label+"_sp"
+ FreeCADGui.ActiveDocument.getObject(original_name).Visibility = False
+ FreeCAD.ActiveDocument.ActiveObject.Label = original_label + "_sp"
FreeCAD.ActiveDocument.recompute()
- found=1
+ found = 1
if "Part::MultiFuse" in sel[0].TypeId:
sayw("doing single copy")
- original_label=make_string(FreeCADGui.Selection.getSelection()[0].Label)
- original_name=FreeCADGui.Selection.getSelection()[0].Name
- n_objs=0
- solids=FreeCAD.ActiveDocument.getObject(FreeCADGui.Selection.getSelection()[0].Name).Shape.Solids
+ original_label = make_string(FreeCADGui.Selection.getSelection()[0].Label)
+ original_name = FreeCADGui.Selection.getSelection()[0].Name
+ n_objs = 0
+ solids = FreeCAD.ActiveDocument.getObject(FreeCADGui.Selection.getSelection()[0].Name).Shape.Solids
for solid in solids:
solids.index(solid)
- n_objs=n_objs+1
+ n_objs = n_objs + 1
simple_copy(sel[0])
- FreeCADGui.ActiveDocument.getObject(original_name).Visibility=False
- FreeCAD.ActiveDocument.ActiveObject.Label=original_label+"_sp"
+ FreeCADGui.ActiveDocument.getObject(original_name).Visibility = False
+ FreeCAD.ActiveDocument.ActiveObject.Label = original_label + "_sp"
FreeCAD.ActiveDocument.recompute()
- found=1
- if found==0:
+ found = 1
+ if found == 0:
say_select_obj()
- if len(sel)>1:
- objs=[]
+ if len(sel) > 1:
+ objs = []
for obj in sel:
- #say(obj.Label)
- if 'Part' in obj.TypeId and 'App::Part' not in sel[0].TypeId and 'Body' not in sel[0].TypeId:
+ # say(obj.Label)
+ if "Part" in obj.TypeId and "App::Part" not in sel[0].TypeId and "Body" not in sel[0].TypeId:
objs.append(obj)
- #say(obj.Label)
- if len(objs)>1:
+ # say(obj.Label)
+ if len(objs) > 1:
sayw("doing union and single copy")
CopyName = FreeCAD.activeDocument().getObject(objs[0].Name).Name
- original_label=make_string(objs[0].Label)
- FreeCAD.activeDocument().addObject("Part::MultiFuse",original_label+"_mp_cp")
+ original_label = make_string(objs[0].Label)
+ FreeCAD.activeDocument().addObject("Part::MultiFuse", original_label + "_mp_cp")
FusionName = FreeCAD.activeDocument().ActiveObject.Name
- #say(FusionName)
+ # say(FusionName)
FreeCAD.activeDocument().getObject(FusionName).Shapes = objs
- FreeCADGui.activeDocument().getObject(CopyName).Visibility=False
- FreeCADGui.ActiveDocument.getObject(FusionName).ShapeColor=FreeCADGui.ActiveDocument.getObject(CopyName).ShapeColor
- FreeCADGui.ActiveDocument.getObject(FusionName).DisplayMode=FreeCADGui.ActiveDocument.getObject(CopyName).DisplayMode
- FreeCAD.ActiveDocument.getObject(FusionName).Label=original_label+"_fd"
+ FreeCADGui.activeDocument().getObject(CopyName).Visibility = False
+ FreeCADGui.ActiveDocument.getObject(FusionName).ShapeColor = FreeCADGui.ActiveDocument.getObject(
+ CopyName,
+ ).ShapeColor
+ FreeCADGui.ActiveDocument.getObject(FusionName).DisplayMode = FreeCADGui.ActiveDocument.getObject(
+ CopyName,
+ ).DisplayMode
+ FreeCAD.ActiveDocument.getObject(FusionName).Label = original_label + "_fd"
FreeCAD.ActiveDocument.recompute()
- if 'Invalid' in FreeCAD.ActiveDocument.getObject(FusionName).State:
+ if "Invalid" in FreeCAD.ActiveDocument.getObject(FusionName).State:
# fusion failed code...
sayerr("fusion failed! doing compound & single copy")
- msg="""Union of parts failed!
... doing Compound & single copy"""
+ msg = """Union of parts failed!
... doing Compound & single copy"""
say_warning(msg)
FreeCAD.ActiveDocument.removeObject(FusionName)
FreeCAD.ActiveDocument.recompute()
- FreeCAD.activeDocument().addObject("Part::Compound",original_label+"_mp")
- FreeCAD.activeDocument().ActiveObject.Links = objs #[FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
- mycompound=FreeCAD.activeDocument().ActiveObject
+ FreeCAD.activeDocument().addObject("Part::Compound", original_label + "_mp")
+ FreeCAD.activeDocument().ActiveObject.Links = (
+ objs # [FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
+ )
+ mycompound = FreeCAD.activeDocument().ActiveObject
FreeCAD.activeDocument().recompute()
simple_copy(FreeCAD.activeDocument().getObject(mycompound.Name))
- FreeCADGui.ActiveDocument.getObject(mycompound.Name).Visibility=False
- FreeCAD.ActiveDocument.ActiveObject.Label=original_label+"_sp"
+ FreeCADGui.ActiveDocument.getObject(mycompound.Name).Visibility = False
+ FreeCAD.ActiveDocument.ActiveObject.Label = original_label + "_sp"
FreeCAD.ActiveDocument.recompute()
- #mw=Gui.getMainWindow()
+ # mw=Gui.getMainWindow()
##c=mw.findChild(QtGui.QPlainTextEdit, "Python console")
##c.clear()
- #r=mw.findChild(QtGui.QTextEdit, "Report view")
- #say(r.toPlainText())
- #if r.toPlainText().find("MultiFusion failed") != -1:
+ # r=mw.findChild(QtGui.QTextEdit, "Report view")
+ # say(r.toPlainText())
+ # if r.toPlainText().find("MultiFusion failed") != -1:
##if "MultiFusion failed" in r.toPlainText():
# sayerr("fusion failed!")
- #say("here again")
- #stop
+ # say("here again")
+ # stop
else:
simple_copy(FreeCAD.activeDocument().getObject(FusionName))
- FreeCADGui.ActiveDocument.getObject(FusionName).Visibility=False
- FreeCAD.ActiveDocument.ActiveObject.Label=original_label+"_sp"
+ FreeCADGui.ActiveDocument.getObject(FusionName).Visibility = False
+ FreeCAD.ActiveDocument.ActiveObject.Label = original_label + "_sp"
FreeCAD.ActiveDocument.recompute()
else:
say_select_obj()
-
+
+
def go_export(fPathName):
global exportV, exportS
sel = FreeCADGui.Selection.getSelection()
if not sel:
FreeCAD.Console.PrintWarning("Select something first!\n\n")
- msg="export VRML from FreeCAD is a python macro that will export simplified VRML of "
- msg+="a (multi)selected Part or fused Part to VRML optimized to Kicad and compatible with Blender "
- msg+="the size of VRML is much smaller compared to the one exported from FC Gui "
- msg+="and the loading/rendering time is also smaller\n"
- msg+="change mesh deviation to increase quality of VRML"
+ msg = "export VRML from FreeCAD is a python macro that will export simplified VRML of "
+ msg += "a (multi)selected Part or fused Part to VRML optimized to Kicad and compatible with Blender "
+ msg += "the size of VRML is much smaller compared to the one exported from FC Gui "
+ msg += "and the loading/rendering time is also smaller\n"
+ msg += "change mesh deviation to increase quality of VRML"
say(msg)
else:
objs = []
- #check_AP()
+ # check_AP()
sel = FreeCADGui.Selection.getSelection()
for obj in sel:
FreeCADGui.Selection.removeSelection(obj)
- wrl_selected=False
+ wrl_selected = False
say(sel[0].Label)
- lbl=sel[0].Label
+ lbl = sel[0].Label
for obj in sel:
- if not 'App::VRMLObject' in obj.TypeId:
- if 'App::Part' in obj.TypeId:
+ if "App::VRMLObject" not in obj.TypeId:
+ if "App::Part" in obj.TypeId:
for o in obj.Group:
- if 'Part' in obj.TypeId:
+ if "Part" in obj.TypeId:
objs.append(o)
else:
objs.append(obj)
- #say(obj.Label)
- #say(obj.Name)
+ # say(obj.Label)
+ # say(obj.Name)
else:
- wrl_selected=True
- if wrl_selected==False:
+ wrl_selected = True
+ if not wrl_selected:
say(fPathName)
# say(objs[0].Label)
# lbl=objs[0].Label
- #say(objs)
- #export(objs, fullFilePathName, scale=None, lbl=None)
+ # say(objs)
+ # export(objs, fullFilePathName, scale=None, lbl=None)
export(objs, fPathName, 0.3937, lbl)
align_colors_to_materials(objs)
- if len(objs) == 1 or 'App::Part' in sel[0].TypeId:
- exportS=True
- if 'App::Part' in sel[0].TypeId:
- step_name=exportStep([sel[0]], fPathName)
- if float(FreeCAD.Version()[0])==1 and float(FreeCAD.Version()[1])==0: ## FC 1.0.x
+ if len(objs) == 1 or "App::Part" in sel[0].TypeId:
+ exportS = True
+ if "App::Part" in sel[0].TypeId:
+ step_name = exportStep([sel[0]], fPathName)
+ if float(FreeCAD.Version()[0]) == 1 and float(FreeCAD.Version()[1]) == 0: ## FC 1.0.x
if step_name is not None:
sayw(step_name)
import step_amend
- found_transp_issue=step_amend.transp_rmv(step_name)
+
+ found_transp_issue = step_amend.transp_rmv(step_name)
if found_transp_issue:
- sayw(step_name+' file amended')
+ sayw(step_name + " file amended")
# need to refresh color changing
FreeCADGui.Selection.addSelection(sel[0])
- #FreeCADGui.Selection.clearSelection()
+ # FreeCADGui.Selection.clearSelection()
else:
- step_name=exportStep(objs, fPathName)
- if float(FreeCAD.Version()[0])==1 and float(FreeCAD.Version()[1])==0: ## FC 1.0.x
+ step_name = exportStep(objs, fPathName)
+ if float(FreeCAD.Version()[0]) == 1 and float(FreeCAD.Version()[1]) == 0: ## FC 1.0.x
if step_name is not None:
sayw(step_name)
import step_amend
- found_transp_issue=step_amend.transp_rmv(step_name)
+
+ found_transp_issue = step_amend.transp_rmv(step_name)
if found_transp_issue:
- sayw(step_name+' file amended')
- #step_amend(fPathName)
+ sayw(step_name + " file amended")
+ # step_amend(fPathName)
else:
- #say("Select ONE single part object !")
- exportS=False
- #QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
+ # say("Select ONE single part object !")
+ exportS = False
+ # QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
else:
- exportS=False;exportV=False
+ exportS = False
+ exportV = False
say("Do not select VRML object(s)!")
say_single_obj()
- #lbl='empty'
- #if len(objs)>0:
+ # lbl='empty'
+ # if len(objs)>0:
# lbl=objs[0].Label
return lbl
+ return None
+
+
###
def align_colors_to_materials(objects):
global exportS, applymaterials, enable_materials
global color_list, color_list_mat, align_vrml_step_colors
-
- newobj_list= objects
-
- if align_vrml_step_colors and enable_materials == 1: #(applymaterials==1):
- sayw('aligning VRML colors to Materials')
- applyDiffuse=0
- color_vector=[]
- for obj in newobj_list: #objs:
- color_vector=[]
- shape1=obj.Shape
- single_color=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
- if(len(single_color)!=len(shape1.Faces)):
- applyDiffuse=0;
- #copy color to all faces
- #else copy singular colors for faces
+
+ newobj_list = objects
+
+ if align_vrml_step_colors and enable_materials == 1: # (applymaterials==1):
+ sayw("aligning VRML colors to Materials")
+ applyDiffuse = 0
+ color_vector = []
+ for obj in newobj_list: # objs:
+ color_vector = []
+ shape1 = obj.Shape
+ single_color = FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
+ if len(single_color) != len(shape1.Faces):
+ applyDiffuse = 0
+ # copy color to all faces
+ # else copy singular colors for faces
else:
- applyDiffuse=1;
+ applyDiffuse = 1
for color in single_color:
color_vector.append((color[0], color[1], color[2], color[3]))
- #sayw(color_vector)
- #sayerr (color_list)
- #sayw(color_list_mat)
- idx=0
- if 'color_list' in globals():
+ # sayw(color_vector)
+ # sayerr (color_list)
+ # sayw(color_list_mat)
+ idx = 0
+ if "color_list" in globals():
for color in color_vector:
if color in color_list:
- #sayerr('found')
+ # sayerr('found')
pos = color_list.index(color)
- #sayw(pos)
- if color_list_mat[pos]!='as is':
+ # sayw(pos)
+ if color_list_mat[pos] != "as is":
if color_list_mat[pos] in material_properties_names:
pos2 = material_properties_names.index(color_list_mat[pos])
- color_vector[idx]=material_properties_diffuse[pos2]
+ color_vector[idx] = material_properties_diffuse[pos2]
else:
- color_vector[idx]=color
- idx+=1
- if(applyDiffuse):
- obj_transparency=FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
- FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor=color_vector
- FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency=obj_transparency
+ color_vector[idx] = color
+ idx += 1
+ if applyDiffuse:
+ obj_transparency = FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
+ FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor = color_vector
+ FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency = obj_transparency
else:
- #say(color_vector)
- #FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor=color_vector[0]
- FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor=color_vector #[0]
- FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency=int(float(color_vector[0][3])*100)
+ # say(color_vector)
+ # FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor=color_vector[0]
+ FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor = color_vector # [0]
+ FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency = int(float(color_vector[0][3]) * 100)
# end test aligning colors
+
+
##
##
def exportStep(objs, ffPathName):
- #Export fused object
+ # Export fused object
global exportS, applymaterials, enable_materials
global color_list, color_list_mat
-
- #if applymaterials==1:
+
+ # if applymaterials==1:
# sayw(color_list); sayw(color_list_mat)
-
- exp_name=objs[0].Label
- #removing not allower chars
- translation_table = dict.fromkeys(map(ord, '<>:"/\|?*,;:\\'), None)
- exp_name=exp_name.translate(translation_table)
- path, fname = os.path.split(ffPathName)
- #fname=os.path.splitext(fname)[0]
+
+ exp_name = objs[0].Label
+ # removing not allower chars
+ translation_table = dict.fromkeys(map(ord, '<>:"/\\|?*,;:\\'), None)
+ exp_name = exp_name.translate(translation_table)
+ path, _fname = os.path.split(ffPathName)
+ # fname=os.path.splitext(fname)[0]
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if prefs.GetBool('stpz_export_enabled'):
+ if prefs.GetBool("stpz_export_enabled"):
#'stpz'
- fullFilePathNameStep=path+os.sep+exp_name+'.stpZ'
- #print('stpZ',fullFilePathNameStep)
+ fullFilePathNameStep = path + os.sep + exp_name + ".stpZ"
+ # print('stpZ',fullFilePathNameStep)
else:
- #not 'stpz'
- fullFilePathNameStep=path+os.sep+exp_name+'.step'
- exportS=True
+ # not 'stpz'
+ fullFilePathNameStep = path + os.sep + exp_name + ".step"
+ exportS = True
if os.path.exists(fullFilePathNameStep):
- say('file exists')
+ say("file exists")
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.question(None, "Info", fullFilePathNameStep+"\nstep file exists, overwrite?",
- QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
+ reply = QtGui.QMessageBox.question(
+ None,
+ "Info",
+ fullFilePathNameStep + "\nstep file exists, overwrite?",
+ QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
+ QtGui.QMessageBox.No,
+ )
if reply == QtGui.QMessageBox.Yes:
# this is where the code relevant to a 'Yes' answer goes
- exportS=True
- pass
+ exportS = True
if reply == QtGui.QMessageBox.No:
# this is where the code relevant to a 'No' answer goes
- exportS=False
- pass
+ exportS = False
if exportS:
## resetting placement TBD for Part & Shape
- if 'App::Part' not in objs[0].TypeId:
- ## evaluate to modify reset placement
+ if "App::Part" not in objs[0].TypeId:
+ ## evaluate to modify reset placement
base_shape = FreeCAD.ActiveDocument.getObject(objs[0].Name)
- if base_shape.Placement.Base != FreeCAD.Vector(0,0,0) or base_shape.Placement.Rotation != FreeCAD.Rotation (0.0, 0.0, 0.0, 1.0):
- newobj=reset_prop_shapes(FreeCAD.ActiveDocument.getObject(objs[0].Name),FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
- new_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ if base_shape.Placement.Base != FreeCAD.Vector(
+ 0,
+ 0,
+ 0,
+ ) or base_shape.Placement.Rotation != FreeCAD.Rotation(0.0, 0.0, 0.0, 1.0):
+ reset_prop_shapes(
+ FreeCAD.ActiveDocument.getObject(objs[0].Name),
+ FreeCAD.ActiveDocument,
+ FreeCAD,
+ FreeCADGui,
+ )
+ new_name = FreeCAD.ActiveDocument.ActiveObject.Name
else:
- newobj=objs[0]
- new_name=objs[0].Name
- #newobj.Label="TEST"
- newobj_list=[FreeCAD.ActiveDocument.getObject(new_name)]
+ objs[0]
+ new_name = objs[0].Name
+ # newobj.Label="TEST"
+ newobj_list = [FreeCAD.ActiveDocument.getObject(new_name)]
else:
import kicadStepUpCMD
+
FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(objs[0].Name))
kicadStepUpCMD.ksuToolsResetPartPlacement.Activated(FreeCAD.ActiveDocument.getObject(objs[0].Name))
- newobj_list=[FreeCAD.ActiveDocument.getObject(objs[0].Name)]
-
- #test aligning colors
-
+ newobj_list = [FreeCAD.ActiveDocument.getObject(objs[0].Name)]
+
+ # test aligning colors
+
# reducing STEP file size
- #NB WriteSurfaceCurveMode parameter get after FC close-reopen
+ # NB WriteSurfaceCurveMode parameter get after FC close-reopen
# paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/General")
# paramGet.SetInt("WriteSurfaceCurveMode", 1)
- #paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/General")
- #paramGet.SetInt("WriteSurfaceCurveMode", 0)
+ # paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/General")
+ # paramGet.SetInt("WriteSurfaceCurveMode", 0)
paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
old_Auth = paramGet.GetString("Author")
old_Comp = paramGet.GetString("Company")
@@ -2954,37 +3160,38 @@ def exportStep(objs, ffPathName):
paramGet.SetString("Author", "kicad StepUp")
paramGet.SetString("Company", "ksu MCAD")
paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
- #old_Scheme = paramGet.GetString("Scheme")
- #if old_Scheme != 'AP214CD':
+ # old_Scheme = paramGet.GetString("Scheme")
+ # if old_Scheme != 'AP214CD':
# paramGet.SetString("Scheme", "AP214CD")
- #paramGetVS1 = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- #old_hScheme1 = paramGetVS1.GetBool("Scheme_203")
- #paramGetVS2 = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- #old_hScheme2 = paramGetVS2.GetBool("Scheme_214")
- #sayw (old_hScheme1)
- #sayw (old_hScheme2)
- #sayw (old_Scheme)
- #stop
- #if old_hScheme1:
+ # paramGetVS1 = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
+ # old_hScheme1 = paramGetVS1.GetBool("Scheme_203")
+ # paramGetVS2 = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
+ # old_hScheme2 = paramGetVS2.GetBool("Scheme_214")
+ # sayw (old_hScheme1)
+ # sayw (old_hScheme2)
+ # sayw (old_Scheme)
+ # stop
+ # if old_hScheme1:
# paramGetVS1.SetBool("Scheme_203",0)
- #if not old_hScheme2:
+ # if not old_hScheme2:
# paramGetVS2.SetBool("Scheme_214",1)
## not to be used paramGet.SetString("Product", "Open CASCADE STEP processor 7.0")
- #print(fullFilePathNameStep)
- #stop
- if fullFilePathNameStep.endswith('stpZ'):
+ # print(fullFilePathNameStep)
+ # stop
+ if fullFilePathNameStep.endswith("stpZ"):
try:
import stepZ
- stepZ.export(newobj_list,fullFilePathNameStep)
+
+ stepZ.export(newobj_list, fullFilePathNameStep)
except:
- sayerr('.stpZ not supported!')
+ sayerr(".stpZ not supported!")
else:
- ImportGui.export(newobj_list,fullFilePathNameStep)
- #del __objs__
- say(fullFilePathNameStep+' written')
+ ImportGui.export(newobj_list, fullFilePathNameStep)
+ # del __objs__
+ say(fullFilePathNameStep + " written")
##ImportGui.export(objs,fullFilePathNameStep)
- #restoring old Author
- #paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
+ # restoring old Author
+ # paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
paramGet.SetString("Author", old_Auth)
paramGet.SetString("Company", old_Comp)
##if old_Scheme != 'AP214CD':
@@ -2993,37 +3200,39 @@ def exportStep(objs, ffPathName):
## paramGetVS1.SetBool("Scheme_203",1)
## paramGetVS2.SetBool("Scheme_214",1)
# paramGet.SetString("Product", old_Prod)
- #say(old_Auth)
- #say(old_Comp)
+ # say(old_Auth)
+ # say(old_Comp)
FreeCAD.activeDocument().recompute()
return fullFilePathNameStep
- return
+ return None
+
+
###
home = expanduser("~")
-#QtGui.QMessageBox.information(None,"info ...","your home path is \r\n"+ home+"\r\n")
-sayw("kicad StepUp version "+str(___ver___))
-#say("tolerance on vertex = "+str(edge_tolerance))
+# QtGui.QMessageBox.information(None,"info ...","your home path is \r\n"+ home+"\r\n")
+sayw("kicad StepUp version " + str(___ver___))
+# say("tolerance on vertex = "+str(edge_tolerance))
say("tolerance on vertex applied")
-if apply_light==True:
+if apply_light:
say("applying Lights")
-if apply_reflex==True:
+if apply_reflex:
say("applying Materials to Shapes")
-say("your home path is "+ home)
-fname_ksu=home+os.sep+'ksu-config.ini'
-ksu_config_fname=fname_ksu
+say("your home path is " + home)
+fname_ksu = home + os.sep + "ksu-config.ini"
+ksu_config_fname = fname_ksu
-default_ksu_config_ini=u"""[info]
+default_ksu_config_ini = """[info]
;; kicad StepUp tools config file utf-8
;; each line starting with a semicolon is a comment
[prefix3D]
;; put here your KISYS3DMOD path or 3D model prefix path or 3D Alias
;; only TWO prefixs are allowed; MUST finish with slash or backslash
-;prefix3D_1 = C:\\Program Files\\KiCad\share\\kicad\\modules\\packages3d\\
+;prefix3D_1 = C:\\Program Files\\KiCad\\share\\kicad\\modules\\packages3d\\
;prefix3D_1 = kicad/share/modules/packages3d/
;prefix3D_1 = /Library/Application Support/kicad/modules/packages3d/
;prefix3D_2 = C:\\extra_packages3d\\
-prefix3D_1 = C:\\Program Files\\KiCad\share\\kicad\\modules\\packages3d\\
+prefix3D_1 = C:\\Program Files\\KiCad\\share\\kicad\\modules\\packages3d\\
prefix3D_2 = kicad/share/modules/packages3d/
[PcbColor]
;; pcb color r,g,b e.g. 0.0,0.5,0.0,light green
@@ -3074,7 +3283,7 @@ def exportStep(objs, ffPathName):
;exportFusing = nofuse #default
exportFusing = nofuse #default
[minimum_drill_size]
-;; minimum drill size to be handled
+;; minimum drill size to be handled
;; set 0.0 to handle all sizes
min_drill_size = 0.0
[last_pcb_path]
@@ -3085,7 +3294,7 @@ def exportStep(objs, ffPathName):
last_fp_path =
[export]
export_to_STEP = yes
-;; export to STEP
+;; export to STEP
;export_to_STEP = yes
;export_to_STEP = no
[Materials]
@@ -3132,10 +3341,11 @@ def exportStep(objs, ffPathName):
;;font size for ksu widget
"""
+
def cfg_read_all():
global ksu_config_fname, default_ksu_config_ini, applymaterials
##ksu pre-set
- global models3D_prefix, models3D_prefix2, models3D_prefix3, models3D_prefix4,default_prefix3d
+ global models3D_prefix, models3D_prefix2, models3D_prefix3, models3D_prefix4, default_prefix3d
global blacklisted_model_elements, col, colr, colg, colb, whitelisted_3Dmodels
global bbox, volume_minimum, height_minimum, idf_to_origin, aux_orig
global base_orig, base_point, bbox_all, bbox_list, whitelisted_model_elements
@@ -3145,39 +3355,37 @@ def cfg_read_all():
global font_section, ini_vars, num_min_lines, animate_result, allow_compound, font_size, grid_orig
global constraints_section, addConstraints, exporting_mode_section, stp_exp_mode
global links_importing_mode_section, links_imp_mode, generate_sketch, edge_tolerance, bklist_dnp
-
- import os, sys, re
+
+ import os
+ import re
from sys import platform as _platform
-
+
# window GUI dimensions parameters
- pt_lnx = False;pt_osx = False;pt_win = False;
if _platform == "linux" or _platform == "linux2":
# linux
- pt_lnx = True
# default_prefix3d = '/usr/share/kicad/modules/packages3d'
- default_prefix3d = '/usr/share/kicad/3dmodels/' # kv7 kv8
+ default_prefix3d = "/usr/share/kicad/3dmodels/" # kv7 kv8
#'/usr/share/kicad/modules/packages3d'
elif _platform == "darwin":
- #osx
- pt_osx = True
- # default_prefix3d = '/Library/Application Support/kicad/packages3d'
- default_prefix3d = '/Applications/KiCad/KiCad.app/Contents/SharedSupport/3dmodels/' # kv7 kv8 ???
- #/Library/Application Support/kicad/modules/packages3d/' wrong location
+ # osx
+ # default_prefix3d = '/Library/Application Support/kicad/packages3d'
+ default_prefix3d = "/Applications/KiCad/KiCad.app/Contents/SharedSupport/3dmodels/" # kv7 kv8 ???
+ # /Library/Application Support/kicad/modules/packages3d/' wrong location
else:
# Windows
- pt_win = True
- #default_prefix3d = os.path.join(os.environ["ProgramFiles"],u'\\KiCad\\share\\kicad\\modules\\packages3d')
+ # default_prefix3d = os.path.join(os.environ["ProgramFiles"],u'\\KiCad\\share\\kicad\\modules\\packages3d')
# default_prefix3d = (os.environ["ProgramFiles"]+u'\\KiCad\\share\\kicad\\modules\\packages3d')
- for i in range(10,5,-1): #searching from kv10 to kv6
- print(os.environ["ProgramFiles"]+u'\\KiCad\\'+str(i)+'.0\\share\\kicad\\3dmodels')
- if os.path.exists(os.environ["ProgramFiles"]+u'\\KiCad\\'+str(i)+'.0\\share\\kicad\\3dmodels'):
- default_prefix3d = (os.environ["ProgramFiles"]+u'\\KiCad\\'+str(i)+'.0\\share\\kicad\\3dmodels') # kv7 kv8
- break # break after founding a valid path
- else:
- default_prefix3d = (os.environ["ProgramFiles"]+u'\\KiCad\\9.0\\share\\kicad\\3dmodels') # kv7 kv8
- #print (default_prefix3d)
- default_prefix3d = re.sub("\\\\", "/", default_prefix3d) #default_prefix3d.replace('\\','/')
- #print (default_prefix3d)
+ for i in range(10, 5, -1): # searching from kv10 to kv6
+ print(os.environ["PROGRAMFILES"] + "\\KiCad\\" + str(i) + ".0\\share\\kicad\\3dmodels")
+ if os.path.exists(os.environ["PROGRAMFILES"] + "\\KiCad\\" + str(i) + ".0\\share\\kicad\\3dmodels"):
+ default_prefix3d = (
+ os.environ["PROGRAMFILES"] + "\\KiCad\\" + str(i) + ".0\\share\\kicad\\3dmodels"
+ ) # kv7 kv8
+ break # break after founding a valid path
+ default_prefix3d = os.environ["PROGRAMFILES"] + "\\KiCad\\9.0\\share\\kicad\\3dmodels" # kv7 kv8
+ # print (default_prefix3d)
+ default_prefix3d = re.sub("\\\\", "/", default_prefix3d) # default_prefix3d.replace('\\','/')
+ # print (default_prefix3d)
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
## if prefs.GetContents() is not None:
## for i,p in enumerate (prefs.GetContents()):
@@ -3188,469 +3396,493 @@ def cfg_read_all():
# for i,p in enumerate (prefs.GetContents()):
# print (p)
# stop
-
- #if prefs.GetContents() is None:
+
+ # if prefs.GetContents() is None:
# print('Creating first time ksu preferences')
# stop #TBD
- #else:
+ # else:
# for i,p in enumerate (prefs.GetContents()):
# print (p)
-
- models3D_prefix = prefs.GetString('prefix3d_1')
-
+
+ models3D_prefix = prefs.GetString("prefix3d_1")
+
# sayw(prefs.GetString('prefix3d_1'))
# sayw(prefs.GetString('prefix3d_2'))
# sayw(prefs.GetString('prefix3d_3'))
# sayw(prefs.GetString('prefix3d_4'))
-
- if len (models3D_prefix) == 0:
- prefs.SetString('prefix3d_1',make_string(default_prefix3d))
- models3D_prefix = prefs.GetString('prefix3d_1')
- models3D_prefix2 = prefs.GetString('prefix3d_2')
- models3D_prefix3 = prefs.GetString('prefix3d_3')
- models3D_prefix4 = prefs.GetString('prefix3d_4')
- light_green = [0.20,0.60,0.40] # std Green
- green = [0.3098,0.4823,0.4078] # Green (79,123,104)
- blue = [0.13,0.40,0.73] # Deep Sea Blue
- red = [1.0,0.16,0.0] # Ferrari Red
- purple = [0.498,0.090,0.424] # oshpark purple #6D0A8E
- darkgreen = [0.180,0.373,0.275] # (45,95,70)
- darkblue = [0.211,0.305,0.455] # (54,79,116)
- lightblue = [0.0,0.298,1.0] # (0,76,255)
- yellow = [0.98,0.98,0.34] #sunshine yellow
- black = [0.18,0.18,0.18] #slick black
- white = [0.973,0.973,0.941] #[0.98,0.92,0.84] #antique white
- pcb_color_values = [light_green,green,blue,red,purple,darkgreen,darkblue,lightblue,yellow,black,white]
- pcb_color_pos = prefs.GetInt('pcb_color')
- pcb_color = pcb_color_values [pcb_color_pos]
+
+ if len(models3D_prefix) == 0:
+ prefs.SetString("prefix3d_1", make_string(default_prefix3d))
+ models3D_prefix = prefs.GetString("prefix3d_1")
+ models3D_prefix2 = prefs.GetString("prefix3d_2")
+ models3D_prefix3 = prefs.GetString("prefix3d_3")
+ models3D_prefix4 = prefs.GetString("prefix3d_4")
+ light_green = [0.20, 0.60, 0.40] # std Green
+ green = [0.3098, 0.4823, 0.4078] # Green (79,123,104)
+ blue = [0.13, 0.40, 0.73] # Deep Sea Blue
+ red = [1.0, 0.16, 0.0] # Ferrari Red
+ purple = [0.498, 0.090, 0.424] # oshpark purple #6D0A8E
+ darkgreen = [0.180, 0.373, 0.275] # (45,95,70)
+ darkblue = [0.211, 0.305, 0.455] # (54,79,116)
+ lightblue = [0.0, 0.298, 1.0] # (0,76,255)
+ yellow = [0.98, 0.98, 0.34] # sunshine yellow
+ black = [0.18, 0.18, 0.18] # slick black
+ white = [0.973, 0.973, 0.941] # [0.98,0.92,0.84] #antique white
+ pcb_color_values = [light_green, green, blue, red, purple, darkgreen, darkblue, lightblue, yellow, black, white]
+ pcb_color_pos = prefs.GetInt("pcb_color")
+ pcb_color = pcb_color_values[pcb_color_pos]
col = []
- col.append(pcb_color[0]);col.append(pcb_color[1]);col.append(pcb_color[2])
- colr=col[0];colg=col[1];colb=col[2]
- #print(colr,colg,colb)
+ col.append(pcb_color[0])
+ col.append(pcb_color[1])
+ col.append(pcb_color[2])
+ colr = col[0]
+ colg = col[1]
+ colb = col[2]
+ # print(colr,colg,colb)
try:
- min_drill_size = float(prefs.GetString('drill_size'))
+ min_drill_size = float(prefs.GetString("drill_size"))
except:
min_drill_size = 0.0
try:
- edge_tolerance = float(prefs.GetString('edge_tolerance'))
+ edge_tolerance = float(prefs.GetString("edge_tolerance"))
except:
edge_tolerance = 0.01
- #print(min_drill_size)
- if prefs.GetBool('vrml_materials'):
- enable_materials=1
- else:
- enable_materials=0
- if prefs.GetBool('mode_virtual'):
- addVirtual=1
- else:
- addVirtual=0
- fusion = prefs.GetBool('make_union')
- export_board_2step = prefs.GetBool('exp_step')
- animate_result = prefs.GetBool('turntable')
- generate_sketch = prefs.GetBool('generate_sketch')
- if prefs.GetBool('asm3_links'):
- links_imp_mode = 'links_allowed'
- else:
- links_imp_mode = 'links_not_allowed'
- if prefs.GetBool('asm3_linkGroups'):
- use_LinkGroups = True
- else:
- use_LinkGroups = False
- aux_orig=0;base_orig=0;base_point=0; grid_orig=0
- #grid_orig -> 0; aux_orig-> 1; base_orig -> 2
- pcb_placement = prefs.GetInt('pcb_placement')
- if pcb_placement == 0:
- grid_orig = 1
- elif pcb_placement == 1:
- aux_orig = 1
+ # print(min_drill_size)
+ enable_materials = 1 if prefs.GetBool("vrml_materials") else 0
+ addVirtual = 1 if prefs.GetBool("mode_virtual") else 0
+ fusion = prefs.GetBool("make_union")
+ export_board_2step = prefs.GetBool("exp_step")
+ animate_result = prefs.GetBool("turntable")
+ generate_sketch = prefs.GetBool("generate_sketch")
+ links_imp_mode = "links_allowed" if prefs.GetBool("asm3_links") else "links_not_allowed"
+ bool(prefs.GetBool("asm3_linkGroups"))
+ aux_orig = 0
+ base_orig = 0
+ base_point = 0
+ grid_orig = 0
+ # grid_orig -> 0; aux_orig-> 1; base_orig -> 2
+ pcb_placement = prefs.GetInt("pcb_placement")
+ if pcb_placement == 0:
+ grid_orig = 1
+ elif pcb_placement == 1:
+ aux_orig = 1
else:
base_orig = 1
- step_exp_mode = prefs.GetInt('step_exp_mode')
+ step_exp_mode = prefs.GetInt("step_exp_mode")
if step_exp_mode == 0:
- stp_exp_mode = 'hierarchy'
+ stp_exp_mode = "hierarchy"
elif step_exp_mode == 1:
- stp_exp_mode = 'flat'
+ stp_exp_mode = "flat"
else:
- stp_exp_mode = 'onelevel'
- m3D_loading_mode = prefs.GetInt('3D_loading_mode')
- if m3D_loading_mode == 0: #old Standard
- #allow_compound = 'True' #old Standard
- allow_compound = 'Hierarchy' #full hierarchy allowed
- if 'LinkView' not in dir(FreeCADGui):
- allow_compound = 'True' #old Standard
- sayw('Links not allowed... \nfalling from Hierarchy to Compound')
+ stp_exp_mode = "onelevel"
+ m3D_loading_mode = prefs.GetInt("3D_loading_mode")
+ if m3D_loading_mode == 0: # old Standard
+ # allow_compound = 'True' #old Standard
+ allow_compound = "Hierarchy" # full hierarchy allowed
+ if "LinkView" not in dir(FreeCADGui):
+ allow_compound = "True" # old Standard
+ sayw("Links not allowed... \nfalling from Hierarchy to Compound")
elif m3D_loading_mode == 1:
- allow_compound = 'Simplified'
+ allow_compound = "Simplified"
elif m3D_loading_mode == 2:
- allow_compound = 'False' #NotAllowedMultiParts
+ allow_compound = "False" # NotAllowedMultiParts
else:
- #allow_compound = 'Hierarchy' #full hierarchy allowed
- allow_compound = 'True' #old Standard
- sketch_constraints = prefs.GetInt('sketch_constraints')
+ # allow_compound = 'Hierarchy' #full hierarchy allowed
+ allow_compound = "True" # old Standard
+ sketch_constraints = prefs.GetInt("sketch_constraints")
if sketch_constraints == 1:
- addConstraints='all'
+ addConstraints = "all"
elif sketch_constraints == 0:
- addConstraints='coincident'
+ addConstraints = "coincident"
elif sketch_constraints == 2:
- addConstraints='full'
+ addConstraints = "full"
else:
- addConstraints='none'
- bbox_all=0; bbox_list=0; whitelisted_model_elements=''
- bbox_opt = prefs.GetString('bbox_list')
- if bbox_opt.upper().find('ALL') !=-1:
- bbox_all=1
- whitelisted_model_elements=''
- elif bbox_opt.upper().find('LIST') !=-1:
- bbox_list=1
- whitelisted_model_elements=bbox_opt.strip('\r\n')
- #whitelisted_models=whitelisted_model_elements.split(",")
- #elif len(bbox_opt) > 0:
-
- bbox=0;blacklisted_model_elements=''
- volume_minimum=0. #0.8 ##1 #mm^3, 0 skipped #global var default
- height_minimum=0. #0.8 ##1 #mm, 0 skipped #global var default
- bklist = prefs.GetString('blacklist')
- bkl_none=False
- bklist_dnp=False
- blacklisted_model_elements=''
- if bklist.lower().find('none') !=-1 or len(bklist) == 0:
- blacklisted_model_elements=''
- bkl_none=True
- elif not(bklist.endswith(";")):
- bklist+=";"
+ addConstraints = "none"
+ bbox_all = 0
+ bbox_list = 0
+ whitelisted_model_elements = ""
+ bbox_opt = prefs.GetString("bbox_list")
+ if bbox_opt.upper().find("ALL") != -1:
+ bbox_all = 1
+ whitelisted_model_elements = ""
+ elif bbox_opt.upper().find("LIST") != -1:
+ bbox_list = 1
+ whitelisted_model_elements = bbox_opt.strip("\r\n")
+ # whitelisted_models=whitelisted_model_elements.split(",")
+ # elif len(bbox_opt) > 0:
+
+ bbox = 0
+ blacklisted_model_elements = ""
+ volume_minimum = 0.0 # 0.8 ##1 #mm^3, 0 skipped #global var default
+ height_minimum = 0.0 # 0.8 ##1 #mm, 0 skipped #global var default
+ bklist = prefs.GetString("blacklist")
+ bkl_none = False
+ bklist_dnp = False
+ blacklisted_model_elements = ""
+ if bklist.lower().find("none") != -1 or len(bklist) == 0:
+ blacklisted_model_elements = ""
+ bkl_none = True
+ elif not (bklist.endswith(";")):
+ bklist += ";"
# print(bklist)
- if bklist.lower().find('volume=') !=-1 and not bkl_none:
- vval=bklist.strip('\r\n')
- bklist_s=bklist
- vvalst=vval.split(";")
- #print(vvalst)
+ if bklist.lower().find("volume=") != -1 and not bkl_none:
+ vval = bklist.strip("\r\n")
+ bklist_s = bklist
+ vvalst = vval.split(";")
+ # print(vvalst)
for l in vvalst:
- #print(l)
- if l.lower().find('volume=') !=-1:
- vvalue=l.split("=")
- volume_minimum=float(vvalue[1].replace(',','.'))
- #print(height_minimum)
- bklist_s=bklist.strip(l)
- #if l.lower().find(';height=') !=-1:
+ # print(l)
+ if l.lower().find("volume=") != -1:
+ vvalue = l.split("=")
+ volume_minimum = float(vvalue[1].replace(",", "."))
+ # print(height_minimum)
+ bklist_s = bklist.strip(l)
+ # if l.lower().find(';height=') !=-1:
# bklist=bklist.strip(';'+l)
- #else:
+ # else:
# bklist=bklist.strip(l+';')
- #print(bklist)
- bklist_n=[x for x in bklist_s.split(";") if x]
- #print('bklist_n',bklist_n)
+ # print(bklist)
+ bklist_n = [x for x in bklist_s.split(";") if x]
+ # print('bklist_n',bklist_n)
##removing empty elements
- bklist=''
+ bklist = ""
for bm in bklist_n:
- bklist+=bm+';'
- #vvalue=vval.split("=")
- #height_minimum=float(vvalue[1])
- #reply = QtGui.QMessageBox.information(None,"info ...","height "+str(height_minimum))
- #vvalue=vval.split("=")
- #volume_minimum=float(vvalue[1])
- #reply = QtGui.QMessageBox.information(None,"info ...","volume "+str(volume_minimum))
- #print('bklist 1',bklist)
- if bklist.lower().find('height=') !=-1 and not bkl_none:
- vval=bklist.strip('\r\n')
- bklist_s=bklist
- vvalst=vval.split(";")
- #print(vvalst)
+ bklist += bm + ";"
+ # vvalue=vval.split("=")
+ # height_minimum=float(vvalue[1])
+ # reply = QtGui.QMessageBox.information(None,"info ...","height "+str(height_minimum))
+ # vvalue=vval.split("=")
+ # volume_minimum=float(vvalue[1])
+ # reply = QtGui.QMessageBox.information(None,"info ...","volume "+str(volume_minimum))
+ # print('bklist 1',bklist)
+ if bklist.lower().find("height=") != -1 and not bkl_none:
+ vval = bklist.strip("\r\n")
+ bklist_s = bklist
+ vvalst = vval.split(";")
+ # print(vvalst)
for l in vvalst:
- #print(l)
- if l.lower().find('height=') !=-1:
- vvalue=l.split("=")
- height_minimum=float(vvalue[1].replace(',','.'))
- #print(height_minimum)
- bklist_s=bklist.strip(l)
- #if l.lower().find(';height=') !=-1:
+ # print(l)
+ if l.lower().find("height=") != -1:
+ vvalue = l.split("=")
+ height_minimum = float(vvalue[1].replace(",", "."))
+ # print(height_minimum)
+ bklist_s = bklist.strip(l)
+ # if l.lower().find(';height=') !=-1:
# bklist=bklist.strip(';'+l)
- #else:
+ # else:
# bklist=bklist.strip(l+';')
- #print(bklist)
- bklist_n=[x for x in bklist.split(";") if x]
- #print(bklist_n)
+ # print(bklist)
+ bklist_n = [x for x in bklist.split(";") if x]
+ # print(bklist_n)
##removing empty elements
- bklist=''
+ bklist = ""
for bm in bklist_n:
- bklist+=bm+';'
- #vvalue=vval.split("=")
- #height_minimum=float(vvalue[1])
- #reply = QtGui.QMessageBox.information(None,"info ...","height "+str(height_minimum))
- if (bklist.lower().find('dnp') !=-1 or bklist.lower().find('dnf') !=-1) and not bkl_none:
- #print('DNP or DNF found!')
- bklist_dnp=True
- #blacklisted_model_elements+='DNP;'
- if bklist.find(';') !=-1 and not bkl_none:
- blacklisted_model_elements=bklist.strip('\r\n')
- #say(bklist);
- bklist_m=[x for x in blacklisted_model_elements.split(";") if x]
+ bklist += bm + ";"
+ # vvalue=vval.split("=")
+ # height_minimum=float(vvalue[1])
+ # reply = QtGui.QMessageBox.information(None,"info ...","height "+str(height_minimum))
+ if (bklist.lower().find("dnp") != -1 or bklist.lower().find("dnf") != -1) and not bkl_none:
+ # print('DNP or DNF found!')
+ bklist_dnp = True
+ # blacklisted_model_elements+='DNP;'
+ if bklist.find(";") != -1 and not bkl_none:
+ blacklisted_model_elements = bklist.strip("\r\n")
+ # say(bklist);
+ bklist_m = [x for x in blacklisted_model_elements.split(";") if x]
##removing empty elements
- #blacklisted_models=blacklisted_model_elements.split(";")
- blacklisted_models= bklist_m
- #say(blacklisted_models)
- #print('bklist',bklist,'height_minimum',height_minimum,'volume_minimum',volume_minimum)
- whitelist = prefs.GetString('whitelist')
- whitel_none=False
- whitelisted_3Dmodels=''
- if whitelist.lower().find('none') !=-1 or len(whitelist) == 0:
- whitelisted_3Dmodels=''
- whitel_none=True
- elif not(whitelist.endswith(";")):
- whitelist+=";"
- if whitelist.find(';') !=-1 or not whitel_none:
- whitelisted_3Dmodels=whitelist.strip('\r\n')
- #say(bklist);
- whitelist_m=[x for x in whitelisted_3Dmodels.split(";") if x]
+ # blacklisted_models=blacklisted_model_elements.split(";")
+ blacklisted_models = bklist_m
+ # say(blacklisted_models)
+ # print('bklist',bklist,'height_minimum',height_minimum,'volume_minimum',volume_minimum)
+ whitelist = prefs.GetString("whitelist")
+ whitel_none = False
+ whitelisted_3Dmodels = ""
+ if whitelist.lower().find("none") != -1 or len(whitelist) == 0:
+ whitelisted_3Dmodels = ""
+ whitel_none = True
+ elif not (whitelist.endswith(";")):
+ whitelist += ";"
+ if whitelist.find(";") != -1 or not whitel_none:
+ whitelisted_3Dmodels = whitelist.strip("\r\n")
+ # say(bklist);
+ whitelist_m = [x for x in whitelisted_3Dmodels.split(";") if x]
##removing empty elements
- #blacklisted_models=blacklisted_model_elements.split(";")
- whitelisted_3Dmodels= whitelist_m
- #say(whitelisted_3Dmodels)
-
+ # blacklisted_models=blacklisted_model_elements.split(";")
+ whitelisted_3Dmodels = whitelist_m
+ # say(whitelisted_3Dmodels)
+
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
dock_mode = pg.GetInt("dockingMode")
if dock_mode == 0:
- docking_mode='float'
+ docking_mode = "float"
elif dock_mode == 1:
- docking_mode='left'
+ docking_mode = "left"
else:
- docking_mode='right'
+ docking_mode = "right"
idf_to_origin = True
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
last_pcb_path = pg.GetString("last_pcb_path")
last_fp_path = pg.GetString("last_fp_path")
-
- #stop
-
+
+ # stop
+
+
##
-#ini_content=read_ini_file()
-ini_content=cfg_read_all()
+# ini_content=read_ini_file()
+ini_content = cfg_read_all()
-#ini_vars[2]=u'd:\extrà 3D'
-#print cfg_get('prefix3D','prefix3d_2')
-#cfg_read_all()
+# ini_vars[2]=u'd:\extrà 3D'
+# print cfg_get('prefix3D','prefix3d_2')
+# cfg_read_all()
# cfg_update_all()
# stop
-#time.sleep(0.5)
-# configParser = ConfigParser.RawConfigParser()
-# configParser = ConfigParser.ConfigParser(allow_no_value = True)
+# time.sleep(0.5)
+# configParser = ConfigParser.RawConfigParser()
+# configParser = ConfigParser.ConfigParser(allow_no_value = True)
# configFilePath = ksu_config_fname
# cfgParsRead(configFilePath)
-#assign params
+# assign params
+
def say_time():
global running_time
-
+
end_milli_time = current_milli_time()
- running_time=(end_milli_time-start_time)/1000
- msg="running time: "+str(round(running_time,3))+"sec"
+ running_time = (end_milli_time - start_time) / 1000
+ msg = "running time: " + str(round(running_time, 3)) + "sec"
say(msg)
+
+
###
+
def get_time():
global running_time
-
+
end_milli_time = current_milli_time()
- running_time=(end_milli_time-start_time)/1000
- #msg="running time: "+str(running_time)+"sec"
- #say(msg)
+ running_time = (end_milli_time - start_time) / 1000
+ # msg="running time: "+str(running_time)+"sec"
+ # say(msg)
+
+
###
-def reset_prop(obj,doc,App,Gui):
- #say('resetting props')
+
+def reset_prop(obj, doc, App, Gui):
+ # say('resetting props')
##try:
- newObj =FreeCAD.ActiveDocument.addObject('Part::Feature',obj.Name)
- newObj.Shape=FreeCAD.ActiveDocument.getObject(obj.Name).Shape
- FreeCAD.ActiveDocument.ActiveObject.Label=FreeCAD.ActiveDocument.getObject(obj.Name).Label
- #tsp = FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
- final_Label=FreeCAD.ActiveDocument.getObject(obj.Name).Label
- #say(final_Label)
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
+ newObj = FreeCAD.ActiveDocument.addObject("Part::Feature", obj.Name)
+ newObj.Shape = FreeCAD.ActiveDocument.getObject(obj.Name).Shape
+ FreeCAD.ActiveDocument.ActiveObject.Label = FreeCAD.ActiveDocument.getObject(obj.Name).Label
+ # tsp = FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
+ final_Label = FreeCAD.ActiveDocument.getObject(obj.Name).Label
+ # say(final_Label)
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
FreeCAD.ActiveDocument.recompute()
- newObjCommon=FreeCAD.activeDocument().addObject("Part::MultiCommon","Common")
- newObjCommon.Shapes = [FreeCAD.activeDocument().getObject(obj.Name),FreeCAD.activeDocument().getObject(newObj.Name),]
- FreeCADGui.activeDocument().getObject(obj.Name).Visibility=False
- FreeCADGui.activeDocument().getObject(newObj.Name).Visibility=False
- FreeCADGui.ActiveDocument.Common.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
- FreeCADGui.ActiveDocument.Common.DisplayMode=FreeCADGui.ActiveDocument.getObject(obj.Name).DisplayMode
+ newObjCommon = FreeCAD.activeDocument().addObject("Part::MultiCommon", "Common")
+ newObjCommon.Shapes = [
+ FreeCAD.activeDocument().getObject(obj.Name),
+ FreeCAD.activeDocument().getObject(newObj.Name),
+ ]
+ FreeCADGui.activeDocument().getObject(obj.Name).Visibility = False
+ FreeCADGui.activeDocument().getObject(newObj.Name).Visibility = False
+ FreeCADGui.ActiveDocument.Common.ShapeColor = FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
+ FreeCADGui.ActiveDocument.Common.DisplayMode = FreeCADGui.ActiveDocument.getObject(obj.Name).DisplayMode
FreeCAD.ActiveDocument.recompute()
# sleep
- FreeCAD.ActiveDocument.addObject('Part::Feature','Common').Shape=FreeCAD.ActiveDocument.Common.Shape
- FreeCAD.ActiveDocument.ActiveObject.Label=final_Label
- rstObj=FreeCAD.ActiveDocument.ActiveObject
- #
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.Common.ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.Common.LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.Common.PointColor
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.Common.DiffuseColor
- #FreeCADGui.ActiveDocument.ActiveObject.Transparency=tsp
+ FreeCAD.ActiveDocument.addObject("Part::Feature", "Common").Shape = FreeCAD.ActiveDocument.Common.Shape
+ FreeCAD.ActiveDocument.ActiveObject.Label = final_Label
+ rstObj = FreeCAD.ActiveDocument.ActiveObject
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.Common.ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.Common.LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.Common.PointColor
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.Common.DiffuseColor
+ # FreeCADGui.ActiveDocument.ActiveObject.Transparency=tsp
FreeCAD.ActiveDocument.removeObject("Common")
FreeCAD.ActiveDocument.recompute()
- #
return rstObj
+
+
###
-def reset_prop_shapes(obj,doc,App,Gui,rmv=None):
+def reset_prop_shapes(obj, doc, App, Gui, rmv=None):
- s=obj.Shape
- #say('resetting props #2')
- r=[]
- t=s.copy()
+ s = obj.Shape
+ # say('resetting props #2')
+ r = []
+ t = s.copy()
for i in t.childShapes():
- #print t.childShapes
- c=i.copy()
- c.Placement=t.Placement.multiply(c.Placement)
- r.append((i,c))
+ # print t.childShapes
+ c = i.copy()
+ c.Placement = t.Placement.multiply(c.Placement)
+ r.append((i, c))
- w=t.replaceShape(r)
- w.Placement=FreeCAD.Placement()
+ w = t.replaceShape(r)
+ w.Placement = FreeCAD.Placement()
Part.show(w)
- #w1 = Part.Solid(w)
- #Part.show(w1)
- #say(w)
+ # w1 = Part.Solid(w)
+ # Part.show(w1)
+ # say(w)
#
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
- #FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
- #FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
- #FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
- #FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
- new_label=make_string(obj.Label)
- #if (obj.TypeId == 'App::Part'):
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
+ # FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
+ # FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
+ # FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
+ # FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
+ new_label = make_string(obj.Label)
+ # if (obj.TypeId == 'App::Part'):
# removesubtree(obj)
- #else:
+ # else:
# FreeCAD.ActiveDocument.removeObject(obj.Name)
# if 0:
# FreeCAD.ActiveDocument.removeObject(obj.Name)
# else:
- say('renaming not in Origin object')
- if rmv == True:
+ say("renaming not in Origin object")
+ if rmv:
FreeCAD.ActiveDocument.removeObject(obj.Name)
else:
FreeCAD.ActiveDocument.getObject(obj.Name).ViewObject.Visibility = False
- FreeCAD.ActiveDocument.getObject(obj.Name).Label = new_label + '_'
+ FreeCAD.ActiveDocument.getObject(obj.Name).Label = new_label + "_"
FreeCAD.ActiveDocument.recompute()
- FreeCAD.ActiveDocument.ActiveObject.Label=new_label
- rstObj=FreeCAD.ActiveDocument.ActiveObject
- #say(rstObj)
+ FreeCAD.ActiveDocument.ActiveObject.Label = new_label
+ return FreeCAD.ActiveDocument.ActiveObject
+ # say(rstObj)
#
- return rstObj
+
###
-def reset_prop_shapes2(obj,doc,App,Gui):
+def reset_prop_shapes2(obj, doc, App, Gui):
- s=obj.Shape
- #say('resetting props #2')
- r=[]
- t=s.copy()
+ s = obj.Shape
+ # say('resetting props #2')
+ r = []
+ t = s.copy()
for i in t.childShapes():
- c=i.copy()
- c.Placement=t.Placement.multiply(c.Placement)
- r.append((i,c))
+ c = i.copy()
+ c.Placement = t.Placement.multiply(c.Placement)
+ r.append((i, c))
- w=t.replaceShape(r)
- w.Placement=FreeCAD.Placement()
+ w = t.replaceShape(r)
+ w.Placement = FreeCAD.Placement()
Part.show(w)
- #say(w)
+ # say(w)
#
- #FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.Part__Feature.ShapeColor
- #FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.Part__Feature.LineColor
- #FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.Part__Feature.PointColor
- #FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.Part__Feature.DiffuseColor
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
- #FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
- new_label=obj.Label
+ # FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.Part__Feature.ShapeColor
+ # FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.Part__Feature.LineColor
+ # FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.Part__Feature.PointColor
+ # FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.Part__Feature.DiffuseColor
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
+ # FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
+ new_label = obj.Label
FreeCAD.ActiveDocument.removeObject(obj.Name)
FreeCAD.ActiveDocument.recompute()
- FreeCAD.ActiveDocument.ActiveObject.Label=new_label
- rstObj=FreeCAD.ActiveDocument.ActiveObject
- #say(rstObj)
+ FreeCAD.ActiveDocument.ActiveObject.Label = new_label
+ return FreeCAD.ActiveDocument.ActiveObject
+ # say(rstObj)
#
- return rstObj
+
###
-def copy_objs(obj,doc):
-
- FreeCAD.ActiveDocument.addObject('Part::Feature',obj.Label).Shape=obj.Shape
- #App.ActiveDocument.ActiveObject.Label=obj.Label
-
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
- #FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
+def copy_objs(obj, doc):
+
+ FreeCAD.ActiveDocument.addObject("Part::Feature", obj.Label).Shape = obj.Shape
+ # App.ActiveDocument.ActiveObject.Label=obj.Label
+
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(obj.Name).LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(obj.Name).PointColor
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
+ # FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(obj.Name).Transparency
FreeCAD.ActiveDocument.recompute()
- #App.ActiveDocument.ActiveObject.ViewObject.Visibility = False
-
+ # App.ActiveDocument.ActiveObject.ViewObject.Visibility = False
+
return FreeCAD.ActiveDocument.ActiveObject
+
+
###
-def copy_objs_BAD(obj,doc,App,Gui):
-
- #cpObj = App.ActiveDocument.addObject('Part::Feature', obj.Label+"cp_")
- #cpObj.Shape = obj.Shape
- #cpObj.Label = obj.Label + "_cp"
- #App.ActiveDocument.addObject('Part::Feature',obj.Label+"cp_").Shape=obj.Shape
- App.ActiveDocument.addObject('Part::Feature',obj.Label).Shape=obj.Shape
- #App.ActiveDocument.ActiveObject.Label=obj.Label
-
- Gui.ActiveDocument.ActiveObject.ShapeColor=Gui.ActiveDocument.getObject(obj.Name).ShapeColor
- Gui.ActiveDocument.ActiveObject.LineColor=Gui.ActiveDocument.getObject(obj.Name).LineColor
- Gui.ActiveDocument.ActiveObject.PointColor=Gui.ActiveDocument.getObject(obj.Name).PointColor
- Gui.ActiveDocument.ActiveObject.DiffuseColor=Gui.ActiveDocument.getObject(obj.Name).DiffuseColor
+
+def copy_objs_BAD(obj, doc, App, Gui):
+
+ # cpObj = App.ActiveDocument.addObject('Part::Feature', obj.Label+"cp_")
+ # cpObj.Shape = obj.Shape
+ # cpObj.Label = obj.Label + "_cp"
+ # App.ActiveDocument.addObject('Part::Feature',obj.Label+"cp_").Shape=obj.Shape
+ App.ActiveDocument.addObject("Part::Feature", obj.Label).Shape = obj.Shape
+ # App.ActiveDocument.ActiveObject.Label=obj.Label
+
+ Gui.ActiveDocument.ActiveObject.ShapeColor = Gui.ActiveDocument.getObject(obj.Name).ShapeColor
+ Gui.ActiveDocument.ActiveObject.LineColor = Gui.ActiveDocument.getObject(obj.Name).LineColor
+ Gui.ActiveDocument.ActiveObject.PointColor = Gui.ActiveDocument.getObject(obj.Name).PointColor
+ Gui.ActiveDocument.ActiveObject.DiffuseColor = Gui.ActiveDocument.getObject(obj.Name).DiffuseColor
App.ActiveDocument.recompute()
- #App.ActiveDocument.ActiveObject.ViewObject.Visibility = False
-
+ # App.ActiveDocument.ActiveObject.ViewObject.Visibility = False
+
return App.ActiveDocument.ActiveObject
+
+
###
def createSolidBBox3(objIn):
s = objIn.Shape
- name=objIn.Label
- FreeCAD.Console.PrintMessage(name+" name ")
+ name = objIn.Label
+ FreeCAD.Console.PrintMessage(name + " name ")
FreeCAD.activeDocument().removeObject(objIn.Name)
# boundBox
boundBox_ = s.BoundBox
- boundBoxLX = boundBox_.XLength
- boundBoxLY = boundBox_.YLength
- boundBoxLZ = boundBox_.ZLength
a = str(boundBox_)
- a,b = a.split('(')
- c = b.split(',')
+ a, b = a.split("(")
+ c = b.split(",")
oripl_X = float(c[0])
oripl_Y = float(c[1])
oripl_Z = float(c[2])
- #say(str(boundBox_))
- #say("Rectangle : "+str(boundBox_.XLength)+" x "+str(boundBox_.YLength)+" x "+str(boundBox_.ZLength))
- #say("_____________________")
- #say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
- obj=FreeCAD.ActiveDocument.addObject('Part::Feature',name)
- obj.Shape=Part.makeBox(boundBox_.XLength, boundBox_.YLength, boundBox_.ZLength, FreeCAD.Vector(oripl_X,oripl_Y,oripl_Z), FreeCAD.Vector(0,0,1))
- bbox_col=bbox_default_col
- if (obj.Name.upper().startswith('X')):
- bbox_col=bbox_x_col
- if (obj.Name.upper().startswith('L')):
- bbox_col=bbox_l_col
- if (obj.Name.upper().startswith('R')):
- bbox_col=bbox_r_col
- if (obj.Name.upper().startswith('C')):
- bbox_col=bbox_c_col
- if (obj.Name.upper().startswith('S')|obj.Name.upper().startswith('Q')|obj.Name.upper().startswith('D')|obj.Name.upper().startswith('T')):
- bbox_col=bbox_IC_col
- FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor=bbox_col
+ # say(str(boundBox_))
+ # say("Rectangle : "+str(boundBox_.XLength)+" x "+str(boundBox_.YLength)+" x "+str(boundBox_.ZLength))
+ # say("_____________________")
+ # say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
+ obj = FreeCAD.ActiveDocument.addObject("Part::Feature", name)
+ obj.Shape = Part.makeBox(
+ boundBox_.XLength,
+ boundBox_.YLength,
+ boundBox_.ZLength,
+ FreeCAD.Vector(oripl_X, oripl_Y, oripl_Z),
+ FreeCAD.Vector(0, 0, 1),
+ )
+ bbox_col = bbox_default_col
+ if obj.Name.upper().startswith("X"):
+ bbox_col = bbox_x_col
+ if obj.Name.upper().startswith("L"):
+ bbox_col = bbox_l_col
+ if obj.Name.upper().startswith("R"):
+ bbox_col = bbox_r_col
+ if obj.Name.upper().startswith("C"):
+ bbox_col = bbox_c_col
+ if (
+ obj.Name.upper().startswith("S")
+ | obj.Name.upper().startswith("Q")
+ | obj.Name.upper().startswith("D")
+ | obj.Name.upper().startswith("T")
+ ):
+ bbox_col = bbox_IC_col
+ FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor = bbox_col
return obj
+
+
###
###
-def createScaledBBox(name,scale):
- # type: box, cylV, cylH
+def createScaledBBox(name, scale):
+ # type: box, cylV, cylH
say(name)
if name == "box_mcad":
type = "cube"
@@ -3658,262 +3890,320 @@ def createScaledBBox(name,scale):
type = "cylinder_vert"
if name == "cylH_mcad":
type = "cylinder_horz"
- say(type+" type")
+ say(type + " type")
# boundBox
boundBoxLX = float(scale[0])
boundBoxLY = float(scale[1])
boundBoxLZ = float(scale[2])
- #oripl_X = float(position[0])
- #oripl_Y = float(position[1])
- #oripl_Z = float(position[2])
- obj=FreeCAD.ActiveDocument.addObject('Part::Feature',name+"_")
- bbox_col=bbox_default_col
+ # oripl_X = float(position[0])
+ # oripl_Y = float(position[1])
+ # oripl_Z = float(position[2])
+ obj = FreeCAD.ActiveDocument.addObject("Part::Feature", name + "_")
+ bbox_col = bbox_default_col
if type == "cube":
- #makeBox(length,width,height,[pnt,dir]) – Make a box located in pnt with the dimensions (length,width,height) By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)
- obj.Shape=Part.makeBox(boundBoxLX, boundBoxLY, boundBoxLZ, FreeCAD.Vector(-boundBoxLX/2,-boundBoxLY/2,0))
- bbox_col=bbox_r_col
-# makeCylinder(radius,height,[pnt,dir,angle])
-# Make a cylinder with a given radius and height By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360
+ # makeBox(length,width,height,[pnt,dir]) - Make a box located in pnt with the dimensions (length,width,height) By default pnt=Vector(0,0,0) and dir=Vector(0,0,1)
+ obj.Shape = Part.makeBox(
+ boundBoxLX,
+ boundBoxLY,
+ boundBoxLZ,
+ FreeCAD.Vector(-boundBoxLX / 2, -boundBoxLY / 2, 0),
+ )
+ bbox_col = bbox_r_col
+ # makeCylinder(radius,height,[pnt,dir,angle])
+ # Make a cylinder with a given radius and height By default pnt=Vector(0,0,0),dir=Vector(0,0,1) and angle=360
if type == "cylinder_vert":
- obj.Shape=Part.makeCylinder(boundBoxLX/2, boundBoxLZ) #, FreeCAD.Vector(-boundBoxLX/2,-boundBoxLY/2,0))
- bbox_col=bbox_c_col
+ obj.Shape = Part.makeCylinder(boundBoxLX / 2, boundBoxLZ) # , FreeCAD.Vector(-boundBoxLX/2,-boundBoxLY/2,0))
+ bbox_col = bbox_c_col
if type == "cylinder_horz":
- obj.Shape=Part.makeCylinder(boundBoxLX/2, boundBoxLY, FreeCAD.Vector(0,-boundBoxLY/2,boundBoxLX/2), FreeCAD.Vector(0,1,0)) #, FreeCAD.Vector(-boundBoxLX/2,-boundBoxLY/2,0))
- bbox_col=bbox_default_col
- FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor=bbox_col
+ obj.Shape = Part.makeCylinder(
+ boundBoxLX / 2,
+ boundBoxLY,
+ FreeCAD.Vector(0, -boundBoxLY / 2, boundBoxLX / 2),
+ FreeCAD.Vector(0, 1, 0),
+ ) # , FreeCAD.Vector(-boundBoxLX/2,-boundBoxLY/2,0))
+ bbox_col = bbox_default_col
+ FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeColor = bbox_col
return obj
+
+
###
+
def Display_info(blacklisted_models):
global bbox_all, bbox_list, fusion, show_messages, last_pcb_path
global height_minimum, volume_minimum, idf_to_origin, ksu_config_fname
global board_base_point_x, board_base_point_y, real_board_pos_x, real_board_pos_y
global animate_result, apply_reflex, apply_reflex_all, addVirtual, fname_sfx
global running_time, missingHeight, whitelisted_3Dmodels
-
- say('info message')
- if blacklisted_model_elements != '':
- sayw("black-listed module \n"+ ''.join(map(str, blacklisted_models)))
- if (show_messages==True):
+
+ say("info message")
+ if blacklisted_model_elements != "":
+ sayw("black-listed module \n" + "".join(map(str, blacklisted_models)))
+ if show_messages:
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Info ...","... black-listed module(s)\r\n"+ ''.join(map(str, blacklisted_models)).replace(',','\n'))
- #FreeCAD.Console.PrintMessage("black-listed module "+ '\r\n'.join(map(str, blacklisted_models)))
- if whitelisted_3Dmodels != '':
- #ssay(whitelisted_3Dmodels)
- sayw("whitelisted_3Dmodels: "+ str(whitelisted_3Dmodels))
- msg="""kicad StepUp ver. """
- msg+=___ver___
- #if len(msgpath)>15:
+ QtGui.QMessageBox.information(
+ None,
+ "Info ...",
+ "... black-listed module(s)\r\n" + "".join(map(str, blacklisted_models)).replace(",", "\n"),
+ )
+ # FreeCAD.Console.PrintMessage("black-listed module "+ '\r\n'.join(map(str, blacklisted_models)))
+ if whitelisted_3Dmodels != "":
+ # ssay(whitelisted_3Dmodels)
+ sayw("whitelisted_3Dmodels: " + str(whitelisted_3Dmodels))
+ msg = """kicad StepUp ver. """
+ msg += ___ver___
+ # if len(msgpath)>15:
# insert_return(msgpath, 15)
- if (idf_to_origin==True):
- new_pos_x=board_base_point_x+real_board_pos_x
- new_pos_y=board_base_point_y+real_board_pos_y
+ if idf_to_origin:
+ new_pos_x = board_base_point_x + real_board_pos_x
+ new_pos_y = board_base_point_y + real_board_pos_y
else:
- new_pos_x=board_base_point_x
- new_pos_y=board_base_point_y
- if (grid_orig==1):
- msg+="
Board Placed @ "+"{0:.2f}".format(board_base_point_x)+";"+"{0:.2f}".format(board_base_point_y)+";0.0"
+ new_pos_x = board_base_point_x
+ new_pos_y = board_base_point_y
+ if grid_orig == 1:
+ msg += "
Board Placed @ " + f"{board_base_point_x:.2f}" + ";" + f"{board_base_point_y:.2f}" + ";0.0"
else:
- msg+="
Board Placed @ "+"{0:.2f}".format(new_pos_x)+";"+"{0:.2f}".format(new_pos_y)+";0.0"
- msg+="
kicad pcb pos: ("+"{0:.2f}".format(real_board_pos_x)+";"+"{0:.2f}".format(real_board_pos_y)+";"+"{0:.2f}".format(0)+")"
- if (bbox_all==1) or (bbox_list==1):
- msg+="
bounding box modules applied"
- if (volume_minimum!=0):
- msg+="
modules with volume less than "+str(volume_minimum)+"mm^3 not included"
- if (height_minimum!=0):
- msg+="
modules with height less than "+str(height_minimum)+"mm not included"
- if (min_drill_size>0):
- msg+="
drills with size less than "+str(min_drill_size)+"mm not included"
- if (min_drill_size==-1):
- msg+="
ALL via drills included"
- if (compound_found):
- msg+="
found multi-part object(s)"
- if addVirtual==0:
- msg+="
Virtual models skipped"
- #msg+="
kicad StepUp config file in:
"+ksu_config_fname+"
location."
+ msg += "
Board Placed @ " + f"{new_pos_x:.2f}" + ";" + f"{new_pos_y:.2f}" + ";0.0"
+ msg += "
kicad pcb pos: (" + f"{real_board_pos_x:.2f}" + ";" + f"{real_board_pos_y:.2f}" + ";" + f"{0:.2f}" + ")"
+ if (bbox_all == 1) or (bbox_list == 1):
+ msg += "
bounding box modules applied"
+ if volume_minimum != 0:
+ msg += (
+ "
modules with volume less than "
+ + str(volume_minimum)
+ + "mm^3 not included"
+ )
+ if height_minimum != 0:
+ msg += (
+ "
modules with height less than "
+ + str(height_minimum)
+ + "mm not included"
+ )
+ if min_drill_size > 0:
+ msg += (
+ "
drills with size less than " + str(min_drill_size) + "mm not included"
+ )
+ if min_drill_size == -1:
+ msg += "
ALL via drills included"
+ if compound_found:
+ msg += "
found multi-part object(s)"
+ if addVirtual == 0:
+ msg += "
Virtual models skipped"
+ # msg+="
kicad StepUp config file in:
"+ksu_config_fname+"
location."
doc = FreeCAD.ActiveDocument
- pcb_name=u'Pcb'+fname_sfx
+ pcb_name = "Pcb" + fname_sfx
pcb_bbx = doc.getObject(pcb_name).Shape.BoundBox
- msg+="
pcb dimensions: ("+"{0:.2f}".format(pcb_bbx.XLength)+";"+"{0:.2f}".format(pcb_bbx.YLength)+";"+"{0:.2f}".format(pcb_bbx.ZLength)+")"
+ msg += (
+ "
pcb dimensions: ("
+ + f"{pcb_bbx.XLength:.2f}"
+ + ";"
+ + f"{pcb_bbx.YLength:.2f}"
+ + ";"
+ + f"{pcb_bbx.ZLength:.2f}"
+ + ")"
+ )
if missingHeight:
- msg+="
MISSING pcb height from stack; forced 1.6mm value"
- msg+="
running time: "+str(round(running_time,2))+"sec"
- msg+="
StepUp configuration options are located in the preferences system of FreeCAD."
- if (grid_orig==1):
- say("Board Placed @ "+"{0:.2f}".format(board_base_point_x)+";"+"{0:.2f}".format(board_base_point_y)+";0.0")
+ msg += "
MISSING pcb height from stack; forced 1.6mm value"
+ msg += "
running time: " + str(running_time) + "sec"
+ msg += "
StepUp configuration options are located in the preferences system of FreeCAD."
+ if grid_orig == 1:
+ say("Board Placed @ " + f"{board_base_point_x:.2f}" + ";" + f"{board_base_point_y:.2f}" + ";0.0")
else:
- say("Board Placed @ "+"{0:.2f}".format(new_pos_x)+";"+"{0:.2f}".format(new_pos_y)+";0.0")
- say("kicad pcb pos: ("+"{0:.2f}".format(real_board_pos_x)+";"+"{0:.2f}".format(real_board_pos_y)+";"+"{0:.2f}".format(0)+")")
- say("pcb dimensions: ("+"{0:.2f}".format(pcb_bbx.XLength)+";"+"{0:.2f}".format(pcb_bbx.YLength)+";"+"{0:.2f}".format(pcb_bbx.ZLength)+")")
+ say("Board Placed @ " + f"{new_pos_x:.2f}" + ";" + f"{new_pos_y:.2f}" + ";0.0")
+ say("kicad pcb pos: (" + f"{real_board_pos_x:.2f}" + ";" + f"{real_board_pos_y:.2f}" + ";" + f"{0:.2f}" + ")")
+ say(
+ "pcb dimensions: ("
+ + f"{pcb_bbx.XLength:.2f}"
+ + ";"
+ + f"{pcb_bbx.YLength:.2f}"
+ + ";"
+ + f"{pcb_bbx.ZLength:.2f}"
+ + ")",
+ )
if missingHeight:
- sayerr('MISSING pcb height from stack; forced 1.6mm value')
- hld=FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View").GetString('HeadlightDirection')
- if len(hld) >0:
- say('Headlight Direction: '+hld)
- if (show_messages==True):
+ sayerr("MISSING pcb height from stack; forced 1.6mm value")
+ hld = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View").GetString("HeadlightDirection")
+ if len(hld) > 0:
+ say("Headlight Direction: " + hld)
+ if show_messages:
QtGui.QApplication.restoreOverrideCursor()
- #RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
- reply = QtGui.QMessageBox.information(None,"Info ...",msg)
- if apply_light==True:
+ # RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
+ QtGui.QMessageBox.information(None, "Info ...", msg)
+ if apply_light:
# attach a light to every visible scene graph
for obj in FreeCAD.ActiveDocument.Objects:
if obj.ViewObject.Visibility:
- obj.ViewObject.RootNode.insertChild(light1(1,1,-1),2)
- obj.ViewObject.RootNode.insertChild(light2(1,1,1),2)
- if animate_result==True and apply_reflex==True: #(apply_reflex==True):
- doc=FreeCAD.ActiveDocument
+ obj.ViewObject.RootNode.insertChild(light1(1, 1, -1), 2)
+ obj.ViewObject.RootNode.insertChild(light2(1, 1, 1), 2)
+ if animate_result and apply_reflex: # (apply_reflex==True):
+ doc = FreeCAD.ActiveDocument
for obj in doc.Objects:
- if ("Board_Geoms" not in obj.Label) and ("Step_Models" not in obj.Label) and ("Step_Virtual_Models" not in obj.Label)\
- and (obj.TypeId != "App::Line") and (obj.TypeId != "App::Plane") and (obj.TypeId != "App::Origin")\
- and (obj.TypeId != "App::Part") and ("Local_CS" not in obj.Name):
+ if (
+ "Board_Geoms" not in obj.Label
+ and "Step_Models" not in obj.Label
+ and "Step_Virtual_Models" not in obj.Label
+ and obj.TypeId not in {"App::Line", "App::Plane", "App::Origin", "App::Part"}
+ and "Local_CS" not in obj.Name
+ ):
if show_data:
say(obj.Name)
- shape1=obj.Shape
- single_color=FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
- if(len(single_color)!=len(shape1.Faces)):
- applyDiffuse=0;
+ shape1 = obj.Shape
+ single_color = FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor
+ if len(single_color) != len(shape1.Faces):
+ applyDiffuse = 0
if show_data:
say(FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeMaterial.DiffuseColor)
- #copy color to all faces
- #else copy singular colors for faces
+ # copy color to all faces
+ # else copy singular colors for faces
else:
- applyDiffuse=1;
+ applyDiffuse = 1
if show_data:
say(FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeMaterial.DiffuseColor)
- color_vector=[]
+ color_vector = []
for color in single_color:
color_vector.append((color[0], color[1], color[2]))
if show_data:
sayw(color_vector)
if show_data:
for f in shape1.Faces:
- sayw('faces')
- #say(f.ShapeMaterial.DiffuseColor)
- #sayerr (color_list)
- #sayw(color_list_mat)
- idx2=0
- if(applyDiffuse):
- if (apply_reflex_all==True):
- shiny=0.6;sun=(201/255, 226/255, 255/255)
+ sayw("faces")
+ # say(f.ShapeMaterial.DiffuseColor)
+ # sayerr (color_list)
+ # sayw(color_list_mat)
+ if applyDiffuse:
+ if apply_reflex_all:
+ shiny = 0.6
+ sun = (201 / 255, 226 / 255, 255 / 255)
if show_data:
sayw(FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeMaterial.Shininess)
- sayerr('multiple colors on faces')
- FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeMaterial.Shininess=shiny
+ sayerr("multiple colors on faces")
+ FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeMaterial.Shininess = shiny
if show_data:
sayw(FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeMaterial.SpecularColor)
- FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeMaterial.SpecularColor=sun
- #for color_v in color_vector:
+ FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeMaterial.SpecularColor = sun
+ # for color_v in color_vector:
# color_vector[idx2]=((color_v[0]*shiny,color_v[1]*shiny,color_v[2]*shiny))
# idx2+=1
- #sayw(color_vector)
- FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor=color_vector
+ # sayw(color_vector)
+ FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor = color_vector
else:
- #say(color_vector)
- shiny=0.4;bright=1.1
- if color_vector[0][0]*bright >1:
- cv0=1
- elif color_vector[0][0]==0:
- cv0=0.25
+ # say(color_vector)
+ shiny = 0.4
+ bright = 1.1
+ if color_vector[0][0] * bright > 1:
+ cv0 = 1
+ elif color_vector[0][0] == 0:
+ cv0 = 0.25
else:
- cv0=color_vector[0][0]*bright
- if color_vector[0][1]*bright >1:
- cv1=1
- elif color_vector[0][1]==0:
- cv1=0.25
+ cv0 = color_vector[0][0] * bright
+ if color_vector[0][1] * bright > 1:
+ cv1 = 1
+ elif color_vector[0][1] == 0:
+ cv1 = 0.25
else:
- cv1=color_vector[0][1]*bright
- if color_vector[0][2]*bright >1:
- cv2=1
- elif color_vector[0][2]==0:
- cv2=0.25
+ cv1 = color_vector[0][1] * bright
+ if color_vector[0][2] * bright > 1:
+ cv2 = 1
+ elif color_vector[0][2] == 0:
+ cv2 = 0.25
else:
- cv2=color_vector[0][2]*bright
- #sayerr(str(cv0)+' '+str(cv1)+' '+str(cv2))
- FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeMaterial.SpecularColor=(cv0,cv1,cv2)
- FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeMaterial.Shininess=shiny
- if (animate_result==True):
- FreeCADGui.ActiveDocument.ActiveView.startAnimating(0,1,0,0.2)
+ cv2 = color_vector[0][2] * bright
+ # sayerr(str(cv0)+' '+str(cv1)+' '+str(cv2))
+ FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeMaterial.SpecularColor = (cv0, cv1, cv2)
+ FreeCADGui.ActiveDocument.getObject(obj.Name).ShapeMaterial.Shininess = shiny
+ if animate_result:
+ FreeCADGui.ActiveDocument.ActiveView.startAnimating(0, 1, 0, 0.2)
+
+
###
def checkFCbug(fcv):
- """ step hierarchy export bug """
- if ((fcv[0] == 0) and (fcv[1] == 17) and (fcv[2] >= 13509) and (fcv[2] < 13515))\
- or ((fcv[0] == 0) and (fcv[1] == 18) and (fcv[2] >= 13509) and (fcv[2] < 13548)):
- #if int(fcv[2]) >= 13509 and int(fcv[2]) < 13548: # or fcv[2] == 13516:
- import Part
- if hasattr(Part, "OCC_VERSION"):
- if (Part.OCC_VERSION=='7.2.0'):
- return True
+ """step hierarchy export bug"""
+ if ((fcv[0] == 0) and (fcv[1] == 17) and (fcv[2] >= 13509) and (fcv[2] < 13515)) or (
+ (fcv[0] == 0) and (fcv[1] == 18) and (fcv[2] >= 13509) and (fcv[2] < 13548)
+ ):
+ # if int(fcv[2]) >= 13509 and int(fcv[2]) < 13548: # or fcv[2] == 13516:
+ import Part
+
+ if hasattr(Part, "OCC_VERSION") and (Part.OCC_VERSION == "7.2.0"):
+ return True
return False
+
+
##
def find_skt_in_Doc():
- """ is returning a list of Sketches and Local_CS and relative Group"""
- #print sel_name
- sk_list=[]
+ """is returning a list of Sketches and Local_CS and relative Group"""
+ # print sel_name
+ sk_list = []
for MObject1 in FreeCAD.ActiveDocument.Objects:
- if MObject1.TypeId=="App::Part":
- #if hasattr(MObject1 ,"Group"):
+ if MObject1.TypeId == "App::Part":
+ # if hasattr(MObject1 ,"Group"):
if MObject1.Group is not None:
for MObject2 in MObject1.Group:
- #print MObject1.Name,MObject2.TypeId
- if 'Sketch' in MObject2.TypeId:
- #print MObject2.TypeId
- if MObject2.Name not in sk_list:
- sk_list.append([MObject2.Name,MObject1.Name])
- #return MObject2.Name, MObject1.Name
- if 'Local_CS_' in MObject2.Name:
- sk_list.append([MObject2.Name,MObject1.Name])
-
- #print 'loop closed'
+ # print MObject1.Name,MObject2.TypeId
+ if "Sketch" in MObject2.TypeId:
+ # print MObject2.TypeId
+ if MObject2.Name not in sk_list:
+ sk_list.append([MObject2.Name, MObject1.Name])
+ # return MObject2.Name, MObject1.Name
+ if "Local_CS_" in MObject2.Name:
+ sk_list.append([MObject2.Name, MObject1.Name])
+
+ # print 'loop closed'
return sk_list
-
+
+
###
+
def Export2MCAD(blacklisted_model_elements):
global bbox_all, bbox_list, fusion, show_messages, last_pcb_path
global height_minimum, volume_minimum, idf_to_origin, ksu_config_fname
global board_base_point_x, board_base_point_y, real_board_pos_x, real_board_pos_y
global animate_result, pcb_path, addVirtual, use_AppPart, force_oldGroups, stp_exp_mode, links_imp_mode
global use_Links, fname_sfx
- say('exporting to MCAD')
+ say("exporting to MCAD")
## exporting
- __objs__=[]
- doc=FreeCAD.ActiveDocument
+ __objs__ = []
+ doc = FreeCAD.ActiveDocument
for obj in doc.Objects:
# do what you want to automate
- if ("Board_Geoms" not in obj.Label) and ("Step_Models" not in obj.Label) and ("Step_Virtual_Models" not in obj.Label)\
- and (obj.TypeId != "App::Line") and (obj.TypeId != "App::Plane") and (obj.TypeId != "App::Origin")\
- and (obj.TypeId != "App::Part") and (obj.TypeId != "Sketcher::SketchObject"):
+ if (
+ "Board_Geoms" not in obj.Label
+ and "Step_Models" not in obj.Label
+ and "Step_Virtual_Models" not in obj.Label
+ and obj.TypeId not in {"App::Line", "App::Plane", "App::Origin", "App::Part", "Sketcher::SketchObject"}
+ ):
FreeCADGui.Selection.addSelection(obj)
__objs__.append(obj)
- filePath=last_pcb_path
- if (bbox_all==1) or (bbox_list==1):
- fpath=filePath+os.sep+doc.Label+"_bbox"+'.step'
+ filePath = last_pcb_path
+ if (bbox_all == 1) or (bbox_list == 1):
+ fpath = filePath + os.sep + doc.Label + "_bbox" + ".step"
else:
- fpath=filePath+os.sep+doc.Label+'.step'
+ fpath = filePath + os.sep + doc.Label + ".step"
# reducing STEP file size
- #NB WriteSurfaceCurveMode parameter get after FC close-reopen
+ # NB WriteSurfaceCurveMode parameter get after FC close-reopen
# paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/General")
# paramGet.SetInt("WriteSurfaceCurveMode", 1)
- #paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/General")
- #paramGet.SetInt("WriteSurfaceCurveMode", 0)
+ # paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/General")
+ # paramGet.SetInt("WriteSurfaceCurveMode", 0)
paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
old_Auth = paramGet.GetString("Author")
old_Comp = paramGet.GetString("Company")
# old_Prod = paramGet.GetString("Product")
paramGet.SetString("Author", "kicad StepUp")
paramGet.SetString("Company", "ksu MCAD")
- #sayw("use_AppPart "+str(use_AppPart)+" force_oldGroups "+str(force_oldGroups)+" fusion "+str(fusion))
- #stop
+ # sayw("use_AppPart "+str(use_AppPart)+" force_oldGroups "+str(force_oldGroups)+" fusion "+str(fusion))
+ # stop
sayw(stp_exp_mode)
# stop
# workaround for OCC7.2 & FC bug
fcv = getFCversion()
fcb = checkFCbug(fcv)
- #sayw(fcv)
- #say(fcv[0])
- #stop
+ # sayw(fcv)
+ # say(fcv[0])
+ # stop
sel = FreeCADGui.Selection.getSelection()
- selN=sel[0].Name
+ selN = sel[0].Name
doc = FreeCAD.ActiveDocument
paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
old_Auth = paramGet.GetString("Author")
@@ -3921,294 +4211,315 @@ def Export2MCAD(blacklisted_model_elements):
# old_Prod = paramGet.GetString("Product")
paramGet.SetString("Author", "kicad StepUp")
paramGet.SetString("Company", "ksu MCAD")
-
- if use_AppPart and not force_oldGroups: # and not fusion:
- #sayw("exporting STEP with Hierarchy")
- #stop
- __ob__=[]
- skl=[]
- skl=find_skt_in_Doc()
- #print skl
- #print sk_name,';',grp_name
+
+ if use_AppPart and not force_oldGroups: # and not fusion:
+ # sayw("exporting STEP with Hierarchy")
+ # stop
+ skl = []
+ skl = find_skt_in_Doc()
+ # print skl
+ # print sk_name,';',grp_name
for sk in skl:
- say('moving sketch from grp')
- #print sk
+ say("moving sketch from grp")
+ # print sk
FreeCAD.ActiveDocument.getObject(sk[1]).removeObject(FreeCAD.ActiveDocument.getObject(sk[0]))
- #FreeCAD.ActiveDocument.getObject(selN).removeObject(FreeCAD.ActiveDocument.getObject(sk_name))
-
- #sayerr(__ob__[0].Name)
- if (fusion==True):
+ # FreeCAD.ActiveDocument.getObject(selN).removeObject(FreeCAD.ActiveDocument.getObject(sk_name))
+
+ # sayerr(__ob__[0].Name)
+ if fusion:
## be careful ... fusion can be heavy or generate FC crash with a lot of objects
## please consider to use bbox or blacklist small objs
# Fuse objects
- doc.addObject("Part::MultiFuse","ksuFusion_")
+ doc.addObject("Part::MultiFuse", "ksuFusion_")
doc.ksuFusion_.Shapes = __objs__
- # doc.ActiveObject.Label=doc.Name+"_union"
+ # doc.ActiveObject.Label=doc.Name+"_union"
doc.recompute()
- doc.addObject('Part::Feature','ksuFusion').Shape=FreeCAD.ActiveDocument.ksuFusion_.Shape
- if (bbox_all==1) or (bbox_list==1):
- doc.ActiveObject.Label=doc.Name+"_bbox_union"
+ doc.addObject("Part::Feature", "ksuFusion").Shape = FreeCAD.ActiveDocument.ksuFusion_.Shape
+ if (bbox_all == 1) or (bbox_list == 1):
+ doc.ActiveObject.Label = doc.Name + "_bbox_union"
else:
- doc.ActiveObject.Label=doc.Name+"_union"
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.ksuFusion_.ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.ksuFusion_.LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.ksuFusion_.PointColor
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.ksuFusion_.DiffuseColor
+ doc.ActiveObject.Label = doc.Name + "_union"
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.ksuFusion_.ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.ksuFusion_.LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.ksuFusion_.PointColor
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.ksuFusion_.DiffuseColor
# Remove the fusion object
doc.removeObject("ksuFusion_")
doc.recompute()
- fobjs=[]
- fused_obj=doc.ActiveObject
+ fobjs = []
+ fused_obj = doc.ActiveObject
FreeCAD.Console.PrintMessage(fused_obj)
fobjs.append(fused_obj)
- if (bbox_all==1) or (bbox_list==1):
- fpath=filePath+os.sep+doc.Label+"_bbox_union"+'.step'
+ if (bbox_all == 1) or (bbox_list == 1):
+ fpath = filePath + os.sep + doc.Label + "_bbox_union" + ".step"
else:
- fpath=filePath+os.sep+doc.Label+"_union"+'.step'
- FreeCAD.Console.PrintMessage(fpath+" fusion path")
+ fpath = filePath + os.sep + doc.Label + "_union" + ".step"
+ FreeCAD.Console.PrintMessage(fpath + " fusion path")
FreeCAD.Console.PrintMessage(fobjs)
- #Export fused object
+ # Export fused object
# reducing STEP file size
- #NB WriteSurfaceCurveMode parameter get after FC close-reopen
+ # NB WriteSurfaceCurveMode parameter get after FC close-reopen
# paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/General")
# paramGet.SetInt("WriteSurfaceCurveMode", 1)
- #paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/General")
- #paramGet.SetInt("WriteSurfaceCurveMode", 0)
- #paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
- #old_Auth = paramGet.GetString("Author")
- #old_Comp = paramGet.GetString("Company")
+ # paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/General")
+ # paramGet.SetInt("WriteSurfaceCurveMode", 0)
+ # paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
+ # old_Auth = paramGet.GetString("Author")
+ # old_Comp = paramGet.GetString("Company")
# old_Prod = paramGet.GetString("Product")
- #paramGet.SetString("Author", "kicad StepUp")
- #paramGet.SetString("Company", "ksu MCAD")
+ # paramGet.SetString("Author", "kicad StepUp")
+ # paramGet.SetString("Company", "ksu MCAD")
## not to be used paramGet.SetString("Product", "Open CASCADE STEP processor 7.0")
- ImportGui.export(fobjs,fpath)
- #restoring old Author
- #paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
+ ImportGui.export(fobjs, fpath)
+ # restoring old Author
+ # paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
# paramGet.SetString("Author", old_Auth)
# paramGet.SetString("Company", old_Comp)
# paramGet.SetString("Product", old_Prod)
- #say(old_Auth)
- #say(old_Comp)
+ # say(old_Auth)
+ # say(old_Comp)
FreeCAD.activeDocument().recompute()
del fobjs
- #ImportGui.export(doc.ActiveObject,filePath+os.sep+doc.Label+'.step')
- elif (fcv[0]==0 and fcv[1]<=16): # FC < 0.17
- sayw('exporting flat FC 0.16')
- ImportGui.export(__objs__,fpath)
- elif (stp_exp_mode == 'hierarchy' and not fcb): # FC not bugged or < 0.17
- sayw('exporting hierarchy')
- __obtoexp__=[]
+ # ImportGui.export(doc.ActiveObject,filePath+os.sep+doc.Label+'.step')
+ elif fcv[0] == 0 and fcv[1] <= 16: # FC < 0.17
+ sayw("exporting flat FC 0.16")
+ ImportGui.export(__objs__, fpath)
+ elif stp_exp_mode == "hierarchy" and not fcb: # FC not bugged or < 0.17
+ sayw("exporting hierarchy")
+ __obtoexp__ = []
# FreeCADGui.Selection.removeSelection(obj)
# FreeCADGui.Selection.addSelection(doc.getObject("Board"))
- __obtoexp__.append(doc.getObject("Board"+fname_sfx))
- ImportGui.export(__obtoexp__,fpath)
+ __obtoexp__.append(doc.getObject("Board" + fname_sfx))
+ ImportGui.export(__obtoexp__, fpath)
del __obtoexp__
- elif (stp_exp_mode == 'onelevel') or (stp_exp_mode == 'hierarchy' and fcb):
- sayw('exporting ONE level hierarchy')
+ elif (stp_exp_mode == "onelevel") or (stp_exp_mode == "hierarchy" and fcb):
+ sayw("exporting ONE level hierarchy")
FreeCADGui.Selection.removeSelection(obj)
- FreeCADGui.Selection.addSelection(doc.getObject("Board"+ fname_sfx))
+ FreeCADGui.Selection.addSelection(doc.getObject("Board" + fname_sfx))
try:
import kicadStepUpCMD
except:
- sayerr('to export STEP it is necessary to use StepUp Workbench
instead of the single Macro
(because of '+str(fcv)+' FC bug)')
- msg="""to export STEP it is necessary to use StepUp Workbench
instead of the single Macro
(because of """+str(fcv)+""" FC bug"""
+ sayerr(
+ "to export STEP it is necessary to use StepUp Workbench
instead of the single Macro
(because of "
+ + str(fcv)
+ + " FC bug)",
+ )
+ msg = (
+ """to export STEP it is necessary to use StepUp Workbench
instead of the single Macro
(because of """
+ + str(fcv)
+ + """ FC bug"""
+ )
say_warning(msg)
for sk in skl:
- say('including sketch in grp')
+ say("including sketch in grp")
FreeCAD.ActiveDocument.getObject(sk[1]).addObject(FreeCAD.ActiveDocument.getObject(sk[0]))
stop
- if fcb:
- cpmode='compound'
- else:
- cpmode='part'
- suffix='_'
- to_export_name=kicadStepUpCMD.deep_copy(doc,cpmode,suffix)
+ cpmode = "compound" if fcb else "part"
+ suffix = "_"
+ to_export_name = kicadStepUpCMD.deep_copy(doc, cpmode, suffix)
# to_export_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #sayw(FreeCAD.ActiveDocument.getObject(to_export_name).Label)
- #say(sel[0])
- __objs__=[]
+ # sayw(FreeCAD.ActiveDocument.getObject(to_export_name).Label)
+ # say(sel[0])
+ __objs__ = []
__objs__.append(FreeCAD.ActiveDocument.getObject(to_export_name))
- #import ImportGui
- ImportGui.export(__objs__,fpath)
- #FreeCAD.ActiveDocument.removeObject(to_export_nam)
+ # import ImportGui
+ ImportGui.export(__objs__, fpath)
+ # FreeCAD.ActiveDocument.removeObject(to_export_nam)
removesubtree(__objs__)
- #del __objs__
- if fcb: # bugged FC version
- sayerr('exported a simplified STEP hierarchy because of '+str(fcv)+' FC bug')
- msg="""exported a simplified STEP hierarchy
because of """+str(fcv)+""" FC bug"""
+ # del __objs__
+ if fcb: # bugged FC version
+ sayerr("exported a simplified STEP hierarchy because of " + str(fcv) + " FC bug")
+ msg = (
+ """exported a simplified STEP hierarchy
because of """
+ + str(fcv)
+ + """ FC bug"""
+ )
say_warning(msg)
-
+
for sk in skl:
- say('including sketch in grp')
+ say("including sketch in grp")
FreeCAD.ActiveDocument.getObject(sk[1]).addObject(FreeCAD.ActiveDocument.getObject(sk[0]))
- #stop
- elif stp_exp_mode == 'flat': # FC >=0.17
+ # stop
+ elif stp_exp_mode == "flat": # FC >=0.17
# need to deselect all 'Part' containers and select all simple objs
- #say('flat')
- if len(sel)==1 and 'App::Part' in sel[0].TypeId: ## flattening a Part hierarchy container
- sayw('flattening Part container')
+ # say('flat')
+ if len(sel) == 1 and "App::Part" in sel[0].TypeId: ## flattening a Part hierarchy container
+ sayw("flattening Part container")
# FreeCADGui.Selection.removeSelection(sel[0])
- __objs__=[]
+ __objs__ = []
for o in FreeCAD.ActiveDocument.getObject(selN).OutListRecursive:
- #print o.TypeId
+ # print o.TypeId
# if 'Part::Feature' in o.TypeId:
- if hasattr(o, 'Shape'):
+ if hasattr(o, "Shape"):
# print o.Label
- # say ('adding ')
+ # say ('adding ')
# FreeCADGui.Selection.addSelection(o)
__objs__.append(o)
- ImportGui.export(__objs__,fpath)
- #del __objs__
+ ImportGui.export(__objs__, fpath)
+ # del __objs__
else:
- sayw('exporting selection')
- ImportGui.export(sel,fpath)
+ sayw("exporting selection")
+ ImportGui.export(sel, fpath)
- if use_AppPart and not force_oldGroups: # and not fusion:
+ if use_AppPart and not force_oldGroups: # and not fusion:
for sk in skl:
- say('including sketch in grp')
+ say("including sketch in grp")
FreeCAD.ActiveDocument.getObject(sk[1]).addObject(FreeCAD.ActiveDocument.getObject(sk[0]))
- #paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
+ # paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Part/STEP")
## restoring old Author
paramGet.SetString("Author", old_Auth)
paramGet.SetString("Company", old_Comp)
# paramGet.SetString("Product", old_Prod)
- #say(old_Auth)
- #say(old_Comp)
- #fusion=False
- mcompound=False #True #to create a Compound instead of a fusion ... to evaluate after Export STEP has improved vejmarie
+ # say(old_Auth)
+ # say(old_Comp)
+ # fusion=False
+ mcompound = (
+ False # True #to create a Compound instead of a fusion ... to evaluate after Export STEP has improved vejmarie
+ )
##mcompound=True
##fusion=True
- if (mcompound==True):
- doc.addObject("Part::Compound","ksuCompound_")
- #say(cObjs)
- doc.ksuCompound_.Links = __objs__ #cObjs
+ if mcompound:
+ doc.addObject("Part::Compound", "ksuCompound_")
+ # say(cObjs)
+ doc.ksuCompound_.Links = __objs__ # cObjs
doc.recompute()
- doc.addObject('Part::Feature','ksuCompound').Shape=FreeCAD.ActiveDocument.ksuCompound_.Shape
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.ksuCompound_.ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.ksuCompound_.LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.ksuCompound_.PointColor
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.ksuCompound_.DiffuseColor
+ doc.addObject("Part::Feature", "ksuCompound").Shape = FreeCAD.ActiveDocument.ksuCompound_.Shape
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.ksuCompound_.ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.ksuCompound_.LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.ksuCompound_.PointColor
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.ksuCompound_.DiffuseColor
# Remove the fusion object
doc.removeObject("ksuCompound_")
doc.recompute()
-
+
stop
for obj in doc.Objects:
# do what you want to automate
FreeCADGui.Selection.removeSelection(obj)
- if blacklisted_model_elements != '':
- sayw("black-listed module \n"+ ''.join(map(str, blacklisted_models)))
- if (show_messages==True):
+ if blacklisted_model_elements != "":
+ sayw("black-listed module \n" + "".join(map(str, blacklisted_models)))
+ if show_messages:
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Info ...","... black-listed module(s)\r\n"+ ''.join(map(str, blacklisted_models)).replace(',','\n'))
- #FreeCAD.Console.PrintMessage("black-listed module "+ '\r\n'.join(map(str, blacklisted_models)))
+ QtGui.QMessageBox.information(
+ None,
+ "Info ...",
+ "... black-listed module(s)\r\n" + "".join(map(str, blacklisted_models)).replace(",", "\n"),
+ )
+ # FreeCAD.Console.PrintMessage("black-listed module "+ '\r\n'.join(map(str, blacklisted_models)))
del __objs__
## Save to disk in native format
- FreeCAD.ActiveDocument=None
- FreeCADGui.ActiveDocument=None
+ FreeCAD.ActiveDocument = None
+ FreeCADGui.ActiveDocument = None
FreeCAD.setActiveDocument(doc.Name)
- FreeCAD.ActiveDocument=FreeCAD.getDocument(doc.Name)
- FreeCADGui.ActiveDocument=FreeCADGui.getDocument(doc.Name)
- if (bbox_all==1) or (bbox_list==1):
- fpath=filePath+os.sep+doc.Name+"_bbox"
- else:
- fpath=filePath+os.sep+doc.Name
- if (fusion==True):
- fpath=fpath+"_union"
- say(fpath+".FCStd")
- #fpath = re.sub("\\\\", "/", fpath)
- #fpath= make_unicode(fpath)
- #freeCADFileName = pcb_path + "/" + doc.Name + ".FCStd" #utf-8 test
- #sayw (pcb_path); sayw(freeCADFileName)
- #fcfilenametest=(freeCADFileName.encode('utf-8'))
- #sayw(fcfilenametest)
- #FreeCAD.getDocument(doc.Name).saveAs(fcfilenametest) #utf-8 test
- #FreeCAD.getDocument(doc.Name).saveAs(freeCADFileName) #utf-8 test
- #stop
-
+ FreeCAD.ActiveDocument = FreeCAD.getDocument(doc.Name)
+ FreeCADGui.ActiveDocument = FreeCADGui.getDocument(doc.Name)
+ fpath = filePath + os.sep + doc.Name + "_bbox" if bbox_all == 1 or bbox_list == 1 else filePath + os.sep + doc.Name
+ if fusion:
+ fpath = fpath + "_union"
+ say(fpath + ".FCStd")
+ # fpath = re.sub("\\\\", "/", fpath)
+ # fpath= make_unicode(fpath)
+ # freeCADFileName = pcb_path + "/" + doc.Name + ".FCStd" #utf-8 test
+ # sayw (pcb_path); sayw(freeCADFileName)
+ # fcfilenametest=(freeCADFileName.encode('utf-8'))
+ # sayw(fcfilenametest)
+ # FreeCAD.getDocument(doc.Name).saveAs(fcfilenametest) #utf-8 test
+ # FreeCAD.getDocument(doc.Name).saveAs(freeCADFileName) #utf-8 test
+ # stop
+
try:
- FreeCAD.getDocument(doc.Name).saveAs((fpath+".FCStd").encode('utf-8')) #bug in FC need to encode utf-8
+ FreeCAD.getDocument(doc.Name).saveAs((fpath + ".FCStd").encode("utf-8")) # bug in FC need to encode utf-8
FreeCAD.ActiveDocument.recompute()
except:
say_warning("error writing FreeCAD file. You do not have write permissions to save file!")
- #FreeCAD.getDocument(doc.Name).Label = doc.Name
- #FreeCADGui.SendMsgToActiveView("Save")
- #FreeCAD.getDocument(doc.Name).save()
- msgpath=filePath+os.sep+doc.Name
- if (bbox_all==1) or (bbox_list==1):
- msgpath=msgpath+"_bbox"
- msg="""kicad StepUp ver. """
- msg+=___ver___
- msg+="
file exported
"+msgpath+'.step'
- #if len(msgpath)>15:
+ # FreeCAD.getDocument(doc.Name).Label = doc.Name
+ # FreeCADGui.SendMsgToActiveView("Save")
+ # FreeCAD.getDocument(doc.Name).save()
+ msgpath = filePath + os.sep + doc.Name
+ if (bbox_all == 1) or (bbox_list == 1):
+ msgpath = msgpath + "_bbox"
+ msg = """kicad StepUp ver. """
+ msg += ___ver___
+ msg += "
file exported
" + msgpath + ".step"
+ # if len(msgpath)>15:
# insert_return(msgpath, 15)
- if (fusion==True):
- msgpath=msgpath+"_union"
- msg+="
fused file exported
"+msgpath+'.step'
- if (idf_to_origin==True):
- new_pos_x=board_base_point_x+real_board_pos_x
- new_pos_y=board_base_point_y+real_board_pos_y
+ if fusion:
+ msgpath = msgpath + "_union"
+ msg += "
fused file exported
" + msgpath + ".step"
+ if idf_to_origin:
+ new_pos_x = board_base_point_x + real_board_pos_x
+ new_pos_y = board_base_point_y + real_board_pos_y
else:
- new_pos_x=board_base_point_x
- new_pos_y=board_base_point_y
- if (grid_orig==1):
- msg+="
Board Placed @ "+"{0:.2f}".format(board_base_point_x)+";"+"{0:.2f}".format(board_base_point_y)+";0.0"
+ new_pos_x = board_base_point_x
+ new_pos_y = board_base_point_y
+ if grid_orig == 1:
+ msg += "
Board Placed @ " + f"{board_base_point_x:.2f}" + ";" + f"{board_base_point_y:.2f}" + ";0.0"
else:
- msg+="
Board Placed @ "+"{0:.2f}".format(new_pos_x)+";"+"{0:.2f}".format(new_pos_y)+";0.0"
- msg+="
kicad pcb pos: ("+"{0:.2f}".format(real_board_pos_x)+";"+"{0:.2f}".format(real_board_pos_y)+";"+"{0:.2f}".format(0)+")"
- if (bbox_all==1) or (bbox_list==1):
- msg+="
bounding box modules applied"
- if (volume_minimum!=0):
- msg+="
modules with volume less than "+str(volume_minimum)+"mm^3 not included"
- if (height_minimum!=0):
- msg+="
modules with height less than "+str(height_minimum)+"mm not included"
- if (min_drill_size!=0):
- msg+="
drills with size less than "+str(min_drill_size)+"mm not included"
- if (compound_found):
- msg+="
found multi-part object(s)"
- if addVirtual==0:
- msg+="
Virtual models skipped"
- #msg+="
kicad StepUp config file in:
"+ksu_config_fname+"
location."
- msg+="
StepUp configuration options are located in the preferences system of FreeCAD."
- if (grid_orig==1):
- say("Board Placed @ "+"{0:.2f}".format(board_base_point_x)+";"+"{0:.2f}".format(board_base_point_y)+";0.0")
+ msg += "
Board Placed @ " + f"{new_pos_x:.2f}" + ";" + f"{new_pos_y:.2f}" + ";0.0"
+ msg += "
kicad pcb pos: (" + f"{real_board_pos_x:.2f}" + ";" + f"{real_board_pos_y:.2f}" + ";" + f"{0:.2f}" + ")"
+ if (bbox_all == 1) or (bbox_list == 1):
+ msg += "
bounding box modules applied"
+ if volume_minimum != 0:
+ msg += (
+ "
modules with volume less than "
+ + str(volume_minimum)
+ + "mm^3 not included"
+ )
+ if height_minimum != 0:
+ msg += (
+ "
modules with height less than "
+ + str(height_minimum)
+ + "mm not included"
+ )
+ if min_drill_size != 0:
+ msg += (
+ "
drills with size less than " + str(min_drill_size) + "mm not included"
+ )
+ if compound_found:
+ msg += "
found multi-part object(s)"
+ if addVirtual == 0:
+ msg += "
Virtual models skipped"
+ # msg+="
kicad StepUp config file in:
"+ksu_config_fname+"
location."
+ msg += "
StepUp configuration options are located in the preferences system of FreeCAD."
+ if grid_orig == 1:
+ say("Board Placed @ " + f"{board_base_point_x:.2f}" + ";" + f"{board_base_point_y:.2f}" + ";0.0")
else:
- say("Board Placed @ "+"{0:.2f}".format(new_pos_x)+";"+"{0:.2f}".format(new_pos_y)+";0.0")
- say("kicad pcb pos: ("+"{0:.2f}".format(real_board_pos_x)+";"+"{0:.2f}".format(real_board_pos_y)+";"+"{0:.2f}".format(0)+")")
+ say("Board Placed @ " + f"{new_pos_x:.2f}" + ";" + f"{new_pos_y:.2f}" + ";0.0")
+ say("kicad pcb pos: (" + f"{real_board_pos_x:.2f}" + ";" + f"{real_board_pos_y:.2f}" + ";" + f"{0:.2f}" + ")")
say_time()
- if (show_messages==True):
+ if show_messages:
QtGui.QApplication.restoreOverrideCursor()
- #RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
- reply = QtGui.QMessageBox.information(None,"Info ...",msg)
- if (animate_result==True):
- FreeCADGui.ActiveDocument.ActiveView.startAnimating(0,1,0,0.2)
+ # RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
+ QtGui.QMessageBox.information(None, "Info ...", msg)
+ if animate_result:
+ FreeCADGui.ActiveDocument.ActiveView.startAnimating(0, 1, 0, 0.2)
+
+
###
def removesubtree(objs):
- def addsubobjs(obj,toremoveset):
+ def addsubobjs(obj, toremoveset):
if isinstance(obj, list):
for o in obj:
toremove.add(o)
for subobj in o.OutList:
- addsubobjs(subobj,toremoveset)
+ addsubobjs(subobj, toremoveset)
else:
toremove.add(obj)
for subobj in obj.OutList:
- addsubobjs(subobj,toremoveset)
+ addsubobjs(subobj, toremoveset)
- import FreeCAD
- toremove=set()
+ toremove = set()
for obj in objs:
- addsubobjs(obj,toremove)
- checkinlistcomplete =False
+ addsubobjs(obj, toremove)
+ checkinlistcomplete = False
while not checkinlistcomplete:
for obj in toremove:
if (obj not in objs) and (frozenset(obj.InList) - toremove):
try:
toremove.remove(obj)
except:
- print('exception remove tree')
- pass
+ print("exception remove tree")
break
else:
checkinlistcomplete = True
@@ -4216,402 +4527,417 @@ def addsubobjs(obj,toremoveset):
try:
obj.Document.removeObject(obj.Name)
except:
- print('exception remove tree')
- pass
+ print("exception remove tree")
###
-def create_compound(count,modelnm): #create compound function when a multipart is loaded
-
+def create_compound(count, modelnm): # create compound function when a multipart is loaded
+
global allow_compound, compound_found, use_Links, use_LinkGroups
-
- counter=0
+
+ counter = 0
for ObJ in FreeCAD.activeDocument().Objects:
- counter+=1
- #sayw(str(counter)+" ");say(str(count))
- if count+1 != counter:
- sayerr('multipart found! ...')
- compound_found=True
- counter=0
+ counter += 1
+ # sayw(str(counter)+" ");say(str(count))
+ if count + 1 != counter:
+ sayerr("multipart found! ...")
+ compound_found = True
+ counter = 0
objs_to_remove = []
for ObJ in FreeCAD.activeDocument().Objects:
- counter+=1
+ counter += 1
if counter > count:
##sayw(ObJ.TypeId)
- if 'App::Plane' not in ObJ.TypeId and 'App::Origin' not in ObJ.TypeId and 'App::Line' not in ObJ.TypeId:
- #FreeCADGui.Selection.addSelection(ObJ)
+ if "App::Plane" not in ObJ.TypeId and "App::Origin" not in ObJ.TypeId and "App::Line" not in ObJ.TypeId:
+ # FreeCADGui.Selection.addSelection(ObJ)
objs_to_remove.append(ObJ)
- #sel = FreeCADGui.Selection.getSelection()
- #lsel = len (sel)
- lotr = len (objs_to_remove)
- #print (lsel)
- #print (sel[lsel-1].Label)
- #for s in sel:
+ # sel = FreeCADGui.Selection.getSelection()
+ # lsel = len (sel)
+ lotr = len(objs_to_remove)
+ # print (lsel)
+ # print (sel[lsel-1].Label)
+ # for s in sel:
# print(s.Label)
- #tobeimproved for App:Links
+ # tobeimproved for App:Links
# sayw(str(objs_to_remove))
- #stop
- #mycompound_new=FreeCAD.activeDocument().ActiveObject
- #sayw (sel.Type)
- #sayw (sel[0].TypeId)
- #stop
- nbr_cmpd=0
- if 'App::LinkGroup' in objs_to_remove[0].TypeId:
+ # stop
+ # mycompound_new=FreeCAD.activeDocument().ActiveObject
+ # sayw (sel.Type)
+ # sayw (sel[0].TypeId)
+ # stop
+ nbr_cmpd = 0
+ if "App::LinkGroup" in objs_to_remove[0].TypeId:
simple_copy_link(objs_to_remove[0])
- mycompound=FreeCAD.activeDocument().ActiveObject
+ mycompound = FreeCAD.activeDocument().ActiveObject
FreeCAD.ActiveDocument.recompute()
removesubtree([objs_to_remove[0]])
- elif 'LinkView' in dir(FreeCADGui):
- if 'App::Part' in objs_to_remove[lotr-1].TypeId: #from FC 0.17-12090 multipart STEPs are loded as App::Part and have a list inverted
- simple_copy_link(objs_to_remove[lotr-1])
- mycompound=FreeCAD.activeDocument().ActiveObject
+ elif "LinkView" in dir(FreeCADGui):
+ if (
+ "App::Part" in objs_to_remove[lotr - 1].TypeId
+ ): # from FC 0.17-12090 multipart STEPs are loded as App::Part and have a list inverted
+ simple_copy_link(objs_to_remove[lotr - 1])
+ mycompound = FreeCAD.activeDocument().ActiveObject
FreeCAD.ActiveDocument.recompute()
- removesubtree([objs_to_remove[lotr-1]])
- elif 'App::Part' in objs_to_remove[0].TypeId: #from FC 0.17-10647 multipart STEPs are loded as App::Part
- sc_list=[]
- recurse_node(objs_to_remove[0],objs_to_remove[0].Placement, sc_list)
- #else: #from FC 0.17-10647 multipart STEPs are loded as App::Part
- sc_list_compound=[]
+ removesubtree([objs_to_remove[lotr - 1]])
+ elif "App::Part" in objs_to_remove[0].TypeId: # from FC 0.17-10647 multipart STEPs are loded as App::Part
+ sc_list = []
+ recurse_node(objs_to_remove[0], objs_to_remove[0].Placement, sc_list)
+ # else: #from FC 0.17-10647 multipart STEPs are loded as App::Part
+ sc_list_compound = []
for o in sc_list:
- if 'Part' in o.TypeId and 'App::Part' not in o.TypeId:
+ if "Part" in o.TypeId and "App::Part" not in o.TypeId:
sc_list_compound.append(o)
FreeCAD.ActiveDocument.recompute()
- #sayw(sc_list_compound)
- #stop
- FreeCAD.activeDocument().addObject("Part::Compound",objs_to_remove[0].Label+"_mp")
- FreeCAD.activeDocument().ActiveObject.Links = sc_list_compound #[FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
- mycompound=FreeCAD.activeDocument().ActiveObject
+ # sayw(sc_list_compound)
+ # stop
+ FreeCAD.activeDocument().addObject("Part::Compound", objs_to_remove[0].Label + "_mp")
+ FreeCAD.activeDocument().ActiveObject.Links = (
+ sc_list_compound # [FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
+ )
+ mycompound = FreeCAD.activeDocument().ActiveObject
if 1:
- #FreeCAD.ActiveDocument.getObject(objs_to_remove[0].Name).removeObjectsFromDocument()
+ # FreeCAD.ActiveDocument.getObject(objs_to_remove[0].Name).removeObjectsFromDocument()
FreeCAD.ActiveDocument.removeObject(objs_to_remove[0].Name)
else:
FreeCADGui.Selection.removeSelection(FreeCADGui.Selection.getSelection()[0])
- #FreeCADGui.Selection.addSelection(FreeCAD.activeDocument().ActiveObject)
+ # FreeCADGui.Selection.addSelection(FreeCAD.activeDocument().ActiveObject)
FreeCAD.ActiveDocument.recompute()
- #simple_copy(FreeCAD.activeDocument().ActiveObject)
- elif 'App::Part' in objs_to_remove[lotr-1].TypeId: #from FC 0.17-12090 multipart STEPs are loded as App::Part and have a list inverted
- sc_list=[]
- recurse_node(objs_to_remove[lotr-1],objs_to_remove[lotr-1].Placement, sc_list)
- #else: #from FC 0.17-10647 multipart STEPs are loded as App::Part
- sc_list_compound=[]
+ # simple_copy(FreeCAD.activeDocument().ActiveObject)
+ elif (
+ "App::Part" in objs_to_remove[lotr - 1].TypeId
+ ): # from FC 0.17-12090 multipart STEPs are loded as App::Part and have a list inverted
+ sc_list = []
+ recurse_node(objs_to_remove[lotr - 1], objs_to_remove[lotr - 1].Placement, sc_list)
+ # else: #from FC 0.17-10647 multipart STEPs are loded as App::Part
+ sc_list_compound = []
for o in sc_list:
- if 'Part' in o.TypeId and 'App::Part' not in o.TypeId and 'Compound' not in o.TypeId:
+ if "Part" in o.TypeId and "App::Part" not in o.TypeId and "Compound" not in o.TypeId:
sc_list_compound.append(o)
FreeCAD.ActiveDocument.recompute()
- #sayw(sc_list_compound)
- #say('Part container found')
- #stop
- FreeCAD.activeDocument().addObject("Part::Compound",objs_to_remove[lotr-1].Label+"_mp")
- FreeCAD.activeDocument().ActiveObject.Links = sc_list_compound #[FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
- mycompound=FreeCAD.activeDocument().ActiveObject
+ # sayw(sc_list_compound)
+ # say('Part container found')
+ # stop
+ FreeCAD.activeDocument().addObject("Part::Compound", objs_to_remove[lotr - 1].Label + "_mp")
+ FreeCAD.activeDocument().ActiveObject.Links = (
+ sc_list_compound # [FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
+ )
+ mycompound = FreeCAD.activeDocument().ActiveObject
if 1:
- #for ob in objs_to_remove:
+ # for ob in objs_to_remove:
# FreeCAD.ActiveDocument.removeObject(ob.Name)
- FreeCAD.ActiveDocument.removeObject(objs_to_remove[lotr-1].Name)
+ FreeCAD.ActiveDocument.removeObject(objs_to_remove[lotr - 1].Name)
FreeCAD.ActiveDocument.removeObject(objs_to_remove[0].Name)
else:
FreeCADGui.Selection.removeSelection(FreeCADGui.Selection.getSelection()[0])
- #FreeCADGui.Selection.addSelection(FreeCAD.activeDocument().ActiveObject)
+ # FreeCADGui.Selection.addSelection(FreeCAD.activeDocument().ActiveObject)
FreeCAD.ActiveDocument.recompute()
- #simple_copy(FreeCAD.activeDocument().ActiveObject)
- elif 'Compound' in objs_to_remove[0].TypeId: #new release will load already a compound
+ # simple_copy(FreeCAD.activeDocument().ActiveObject)
+ elif "Compound" in objs_to_remove[0].TypeId: # new release will load already a compound
for Obj in objs_to_remove:
- if 'Compound' in Obj.TypeId:
- nbr_cmpd+=1
+ if "Compound" in Obj.TypeId:
+ nbr_cmpd += 1
if nbr_cmpd == 1:
- mycompound=FreeCAD.activeDocument().getObject(objs_to_remove[0].Name)
- #FreeCADGui.Selection.addSelection(mycompound)
- sayw('single Compound part')
- #print sel[0].TypeId
- #stop
- else:
- #if nbr_cmpd > 1 or nbr_cmpd == 0:
- #if 'App::Part' not in sel[0].TypeId:
- #if nbr_cmpd > 1 or nbr_cmpd == 0: #new release will load already a compound
- if nbr_cmpd>=1:
- sayw('multi Compound part ...')
- sayw('... doing compound')
- sc_list_compound=[]
+ mycompound = FreeCAD.activeDocument().getObject(objs_to_remove[0].Name)
+ # FreeCADGui.Selection.addSelection(mycompound)
+ sayw("single Compound part")
+ # print sel[0].TypeId
+ # stop
+ else:
+ # if nbr_cmpd > 1 or nbr_cmpd == 0:
+ # if 'App::Part' not in sel[0].TypeId:
+ # if nbr_cmpd > 1 or nbr_cmpd == 0: #new release will load already a compound
+ if nbr_cmpd >= 1:
+ sayw("multi Compound part ...")
+ sayw("... doing compound")
+ sc_list_compound = []
for o in objs_to_remove:
- if 'Compound2' in o.TypeId or 'App::LinkGroup' in o.TypeId:
+ if "Compound2" in o.TypeId or "App::LinkGroup" in o.TypeId:
sc_list_compound.append(o)
if len(sc_list_compound) == 0:
for o in objs_to_remove:
- if 'Part' in o.TypeId and 'App::Part' not in o.TypeId:
+ if "Part" in o.TypeId and "App::Part" not in o.TypeId:
sc_list_compound.append(o)
- #print (sc_list_compound)
- FreeCAD.ActiveDocument.addObject("Part::Compound",'MultiPart')
- FreeCAD.ActiveDocument.ActiveObject.Links = sc_list_compound #[FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
+ # print (sc_list_compound)
+ FreeCAD.ActiveDocument.addObject("Part::Compound", "MultiPart")
+ FreeCAD.ActiveDocument.ActiveObject.Links = (
+ sc_list_compound # [FreeCAD.activeDocument().Part__Feature,FreeCAD.activeDocument().Shape,]
+ )
FreeCADGui.Selection.clearSelection()
- mycompound=FreeCAD.ActiveDocument.ActiveObject
- #FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.ActiveObject)
+ mycompound = FreeCAD.ActiveDocument.ActiveObject
+ # FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.ActiveObject)
FreeCAD.ActiveDocument.recompute()
- #stop
- modelnm_norm=make_string(modelnm) #to manage utf-8
- FreeCAD.ActiveDocument.addObject('Part::Feature',modelnm_norm).Shape=FreeCAD.ActiveDocument.getObject(mycompound.Name).Shape
+ # stop
+ modelnm_norm = make_string(modelnm) # to manage utf-8
+ FreeCAD.ActiveDocument.addObject("Part::Feature", modelnm_norm).Shape = FreeCAD.ActiveDocument.getObject(
+ mycompound.Name,
+ ).Shape
mynewObj = FreeCAD.ActiveDocument.ActiveObject
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(mycompound.Name).ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(mycompound.Name).LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(mycompound.Name).PointColor
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(mycompound.Name).DiffuseColor
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(
+ mycompound.Name,
+ ).ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(
+ mycompound.Name,
+ ).LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(
+ mycompound.Name,
+ ).PointColor
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject(
+ mycompound.Name,
+ ).DiffuseColor
## if use_Links: # compound2 colors to be fixed
## FreeCADGui.ActiveDocument.ActiveObject.mapShapeColors(FreeCAD.ActiveDocument)
- #FreeCAD.ActiveDocument.removeObject(mycompound.Name)
- #FreeCAD.ActiveDocument.recompute()
- #stop
- #for ob in objs_to_remove:
+ # FreeCAD.ActiveDocument.removeObject(mycompound.Name)
+ # FreeCAD.ActiveDocument.recompute()
+ # stop
+ # for ob in objs_to_remove:
# FreeCAD.ActiveDocument.removeObject(ob.Name)
- #removesubtree(FreeCADGui.Selection.getSelection())
+ # removesubtree(FreeCADGui.Selection.getSelection())
removesubtree([mycompound])
## reference mode for labels
- mynewObj.Label=modelnm_norm
- #sayerr('HERE')
- #workaround to remove all extra objects instead of searching for top level container
+ mynewObj.Label = modelnm_norm
+ # sayerr('HERE')
+ # workaround to remove all extra objects instead of searching for top level container
for o in objs_to_remove:
- try:
+ with contextlib.suppress(BaseException):
FreeCAD.ActiveDocument.removeObject(o.Name)
- except:
- pass
- #App.ActiveDocument.getObject(FreeCADGui.Selection.getSelection()[0].Name).removeObjectsFromDocument()
- #App.ActiveDocument.removeObject(FreeCADGui.Selection.getSelection()[0].Name)
- #removesubtree(mycompound.Name)
+ # App.ActiveDocument.getObject(FreeCADGui.Selection.getSelection()[0].Name).removeObjectsFromDocument()
+ # App.ActiveDocument.removeObject(FreeCADGui.Selection.getSelection()[0].Name)
+ # removesubtree(mycompound.Name)
FreeCAD.ActiveDocument.recompute()
- #stop
+ # stop
FreeCADGui.Selection.clearSelection()
+
+
###
+
def find_top_container(objs_list):
- '''searching for top level Part container'''
+ """searching for top level Part container"""
ap_list = []
cp_list = []
ag_list = []
for o in objs_list:
- #say(o.Label)
- if o.TypeId == 'App::Part':
+ # say(o.Label)
+ if o.TypeId == "App::Part":
ap_list.append(o)
- elif o.TypeId == 'Part::Compound2':
+ elif o.TypeId == "Part::Compound2":
cp_list.append(o)
- elif o.TypeId == 'App::LinkGroup':
+ elif o.TypeId == "App::LinkGroup":
ag_list.append(o)
- top_ap=None
- top_cp=None
+ top_ap = None
+ top_cp = None
for ap in ap_list:
if len(ap.InListRecursive) == 0:
top_ap = ap
break
- #say(str(ap_list));stop
+ # say(str(ap_list));stop
if top_ap is not None:
say(top_ap.Label)
- sayw('multi Part found! ...')
+ sayw("multi Part found! ...")
return top_ap
- else:
- for cp in cp_list:
- if len(cp.InListRecursive) == 0:
- top_cp = cp
- say(top_cp.Label)
- sayw('multi Compound found! ...')
- break
+ for cp in cp_list:
+ if len(cp.InListRecursive) == 0:
+ top_cp = cp
+ say(top_cp.Label)
+ sayw("multi Compound found! ...")
+ break
if top_cp is not None:
return top_cp
- else:
- top_ag = None
- for ag in ag_list:
- if len(ag.InListRecursive) == 0:
- top_ag = ag
- say(top_ag.Label)
- sayw('multi LinkGroup found! ...')
- break
- return top_ag
+ top_ag = None
+ for ag in ag_list:
+ if len(ag.InListRecursive) == 0:
+ top_ag = ag
+ say(top_ag.Label)
+ sayw("multi LinkGroup found! ...")
+ break
+ return top_ag
+
+
##
+
def check_wrl_transparency(step_module):
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
step_transparency = 0
- Led_enabled = prefs.GetBool('transparency_material_led_enabled')
- Glass_enabled = prefs.GetBool('transparency_material_glass_enabled')
+ Led_enabled = prefs.GetBool("transparency_material_led_enabled")
+ Glass_enabled = prefs.GetBool("transparency_material_glass_enabled")
if Led_enabled or Glass_enabled:
- #sayw('force transparency for glass or led materials'
- if step_module.lower().endswith('wrl'):
+ # sayw('force transparency for glass or led materials'
+ if step_module.lower().endswith("wrl"):
if os.path.exists(step_module): # a wrl model could be missing
- read_mode = 'r'
- if (sys.version_info > (3, 0)): #py3
- read_mode = 'rb'
- LedM=b'material USE LED'
- GlassM=b'material USE GLASS'
- else:
- read_mode = 'r'
- LedM='material USE LED'
- GlassM='material USE GLASS'
+ read_mode = "r"
+ read_mode = "rb"
+ LedM = b"material USE LED"
+ GlassM = b"material USE GLASS"
with builtin.open(step_module, read_mode) as f:
- #FreeCAD.Console.PrintError(step_module)
- #FreeCAD.Console.PrintError(' WRL MATERIALS\n')
+ # FreeCAD.Console.PrintError(step_module)
+ # FreeCAD.Console.PrintError(' WRL MATERIALS\n')
model_content = f.read()
if Led_enabled and LedM in model_content:
- sayw('force transparency for led materials')
+ sayw("force transparency for led materials")
step_transparency = 30
if Glass_enabled and GlassM in model_content:
- sayw('force transparency for glass materials')
+ sayw("force transparency for glass materials")
step_transparency = 70
- elif step_module.lower().endswith('wrz'):
- read_mode = 'r'
- if (sys.version_info > (3, 0)): #py3
- read_mode = 'rb'
- LedM=b'material USE LED'
- GlassM=b'material USE GLASS'
- else:
- read_mode = 'r'
- LedM='material USE LED'
- GlassM='material USE GLASS'
+ elif step_module.lower().endswith("wrz"):
+ read_mode = "r"
+ read_mode = "rb"
+ LedM = b"material USE LED"
+ GlassM = b"material USE GLASS"
try:
with gz.open(step_module, read_mode) as f:
model_content = f.read()
- #FreeCAD.Console.PrintError(model_content)
+ # FreeCAD.Console.PrintError(model_content)
if Led_enabled and LedM in model_content:
- sayw('force transparency for led materials')
+ sayw("force transparency for led materials")
step_transparency = 30
if Glass_enabled and GlassM in model_content:
- sayw('force transparency for glass materials')
+ sayw("force transparency for glass materials")
step_transparency = 70
except:
step_transparency = 0
- sayerr('wrz transparency NOT supported')
+ sayerr("wrz transparency NOT supported")
return step_transparency
+
+
##
def findModelPath(model_type, path_list):
- """ Find module in all paths and types specified """
- global models3D_prefix, models3D_prefix2, models3D_prefix3, models3D_prefix4,default_prefix3d
+ """Find module in all paths and types specified"""
+ global models3D_prefix, models3D_prefix2, models3D_prefix3, models3D_prefix4, default_prefix3d
- module_path='not-found'
+ module_path = "not-found"
# model_type = [step_module,step_module_lw,step_module_up,step_module2,step_module2_up,step_module3,step_module3_up,step_module4,step_module4_up,step_module5,step_module5_up]
# path_list = [models3D_prefix,models3D_prefix2,models3D_prefix3,models3D_prefix4]
- path_list = list(filter(None, path_list)) #removing empty paths
+ path_list = list(filter(None, path_list)) # removing empty paths
# sayw('searching models:'+str(model_type))
- say('on '+str(len(path_list))+' paths: '+str(path_list))
+ say("on " + str(len(path_list)) + " paths: " + str(path_list))
for model in model_type:
- if (module_path=='not-found'):
+ if module_path == "not-found":
# sayerr('trying '+model)
- if os.path.exists(model): # absolute path
- module_path=model
+ if os.path.exists(model): # absolute path
+ module_path = model
break
for mpath in path_list:
- if (module_path=='not-found'):
- model=model.replace(u'"', u'') # strip out '"'
+ if module_path == "not-found":
+ model = model.replace('"', "") # strip out '"'
mpath_U = re.sub("\\\\", "/", mpath)
mpath_U = re.sub("//", "/", mpath_U)
# mpath_U = mpath_U.replace("\\", "/")
- utf_path=os.path.join(make_unicode(mpath_U),make_unicode(model))
+ utf_path = os.path.join(make_unicode(mpath_U), make_unicode(model))
# sayerr('trying '+utf_path)
if os.path.exists(utf_path):
- module_path=utf_path
+ module_path = utf_path
# say('model found! on path: '+re.sub("\\\\", "/", module_path))
break
return module_path
+
+
##
def restore_specular(obj_pre_list):
-
- doc=FreeCAD.ActiveDocument
- objs=doc.Objects
+
+ doc = FreeCAD.ActiveDocument
+ objs = doc.Objects
os = 0.5
ds = 0.05
- restored=False
+ restored = False
for o in objs:
if o not in obj_pre_list:
# print(o.Label)
- if (hasattr(o,'ViewObject')):
- if (hasattr(o.ViewObject,'ShapeMaterial')):
- # print(o.ViewObject.ShapeMaterial.SpecularColor)
- if (hasattr(o.ViewObject,'DiffuseColor')):
- d=o.ViewObject.DiffuseColor
- s=o.ViewObject.ShapeMaterial.SpecularColor
- if (s[0]>=os and s[1]>=os and s[2]>=os):
- o.ViewObject.ShapeMaterial.SpecularColor=(ds, ds, ds) #(0.0, 0.0, 0.0)
- o.ViewObject.DiffuseColor=d
- restored=True
+ if (hasattr(o, "ViewObject")) and (hasattr(o.ViewObject, "ShapeMaterial")):
+ # print(o.ViewObject.ShapeMaterial.SpecularColor)
+ if hasattr(o.ViewObject, "DiffuseColor"):
+ d = o.ViewObject.DiffuseColor
+ s = o.ViewObject.ShapeMaterial.SpecularColor
+ if s[0] >= os and s[1] >= os and s[2] >= os:
+ o.ViewObject.ShapeMaterial.SpecularColor = (ds, ds, ds) # (0.0, 0.0, 0.0)
+ o.ViewObject.DiffuseColor = d
+ restored = True
if restored:
- FreeCAD.Console.PrintWarning('default specular color restored\n')
+ FreeCAD.Console.PrintWarning("default specular color restored\n")
+
##
-def Load_models(pcbThickness,modules):
+def Load_models(pcbThickness, modules):
global off_x, off_y, volume_minimum, height_minimum, bbox_all, bbox_list
global whitelisted_model_elements
- global models3D_prefix, models3D_prefix2, models3D_prefix3, models3D_prefix4,default_prefix3d
+ global models3D_prefix, models3D_prefix2, models3D_prefix3, models3D_prefix4, default_prefix3d
global last_pcb_path, full_placement, whitelisted_3Dmodels
global allow_compound, compound_found, bklist, force_transparency, warning_nbr, use_AppPart
global conv_offs, use_Links, links_imp_mode, use_pypro, use_LinkGroups, fname_sfx
-
- #say (modules)
- missing_models = ''
- compound_found=False
+
+ # say (modules)
+ missing_models = ""
+ compound_found = False
loaded_models = []
loaded_model_objs = []
loaded_models_skipped = []
- createScaledObjs=False #box and cyl from wrl scale params
- virtual_nbr=0
- virtualTop_nbr=0
- virtualBot_nbr=0
- modelTop_nbr=0
- modelBot_nbr=0
- mod_cnt=0
- top_name='Top'+fname_sfx
- bot_name='Bot'+fname_sfx
- topV_name='TopV'+fname_sfx
- botV_name='BotV'+fname_sfx
- stepM_name='Step_Models'+fname_sfx
- stepV_name='Step_Virtual_Models'+fname_sfx
-
- my_hide_list=""
+ createScaledObjs = False # box and cyl from wrl scale params
+ virtual_nbr = 0
+ virtualTop_nbr = 0
+ virtualBot_nbr = 0
+ modelTop_nbr = 0
+ modelBot_nbr = 0
+ mod_cnt = 0
+ top_name = "Top" + fname_sfx
+ bot_name = "Bot" + fname_sfx
+ topV_name = "TopV" + fname_sfx
+ botV_name = "BotV" + fname_sfx
+ stepM_name = "Step_Models" + fname_sfx
+ stepV_name = "Step_Virtual_Models" + fname_sfx
+
+ my_hide_list = ""
for i in range(len(modules)):
- step_module=modules[i][0]
+ step_module = modules[i][0]
module_container = step_module
- #print(type(step_module)) #maui test py3
- #sayw('added '+str(i)+' model(s)')
+ # print(type(step_module)) #maui test py3
+ # sayw('added '+str(i)+' model(s)')
# say(' modelname= '+modules[i][0]+' '+str(i));
# say(' modelLayer= '+modules[i][4]+' '+str(i));
# say(' modelparams '+str(modules[i])+' '+str(i));
- #FreeCAD.Console.PrintMessage('step-module '+step_module)
- encoded=0
- sayw(step_module) # utf-8 test
- if step_module == 'no3Dmodel' or modules[i][4] == 'noLayer':
- say('virtual skipped')
- elif (step_module.startswith(':')) or (step_module.startswith('":')): #alias 3D path
- step_module_t=step_module.split(':', 1)[-1]
- step_module=step_module_t.split(':', 1)[-1]
- #step_module=step_module.decode("utf-8").replace(u'"', u'') # name with spaces
- step_module=step_module.replace(u'"', u'') # name with spaces
- if (step_module.startswith('/')) or (step_module.startswith('\\')):
- step_module=step_module[1:]
- encoded=1
- #say(step_module)
- #step_module=step_module_t[1]
- #say(step_module.split(':')[1:])
- say('adjusting Alias Path')
- say('step-module-replaced '+step_module)
- elif (step_module.find('${HOME}')!=-1): #local 3D path
- #step_module=step_module.replace('${KIPRJMOD}', '.')
+ # FreeCAD.Console.PrintMessage('step-module '+step_module)
+ encoded = 0
+ sayw(step_module) # utf-8 test
+ if step_module == "no3Dmodel" or modules[i][4] == "noLayer":
+ say("virtual skipped")
+ elif step_module.startswith((":", '":')): # alias 3D path
+ step_module_t = step_module.split(":", 1)[-1]
+ step_module = step_module_t.split(":", 1)[-1]
+ # step_module=step_module.decode("utf-8").replace(u'"', u'') # name with spaces
+ step_module = step_module.replace('"', "") # name with spaces
+ if step_module.startswith(("/", "\\")):
+ step_module = step_module[1:]
+ encoded = 1
+ # say(step_module)
+ # step_module=step_module_t[1]
+ # say(step_module.split(':')[1:])
+ say("adjusting Alias Path")
+ say("step-module-replaced " + step_module)
+ elif step_module.find("${HOME}") != -1: # local 3D path
+ # step_module=step_module.replace('${KIPRJMOD}', '.')
home = expanduser("~")
- #step_module=step_module.decode("utf-8").replace(u'${HOME}', home.decode("utf-8"))
- step_module=step_module.replace(u'${HOME}', home)
- step_module=step_module.replace(u'"', u'') # name with spaces
- encoded=1
- say('adjusting Local Path')
- say('step-module-replaced '+step_module)
- elif (step_module.find('${KIPRJMOD}')!=-1): #local 3D path
+ # step_module=step_module.decode("utf-8").replace(u'${HOME}', home.decode("utf-8"))
+ step_module = step_module.replace("${HOME}", home)
+ step_module = step_module.replace('"', "") # name with spaces
+ encoded = 1
+ say("adjusting Local Path")
+ say("step-module-replaced " + step_module)
+ elif step_module.find("${KIPRJMOD}") != -1: # local 3D path
step_module = re.sub("\\\\", "/", step_module)
- #if isinstance(step_module, str):
+ # if isinstance(step_module, str):
# step_module = step_module.decode('unicode_escape')
last_pcb_path = re.sub("\\\\", "/", last_pcb_path)
- #if isinstance(last_pcb_path, str):
+ # if isinstance(last_pcb_path, str):
# last_pcb_path = last_pcb_path.decode('unicode_escape')
- step_module=step_module.replace(u'${KIPRJMOD}', last_pcb_path)
- #sm=step_module
- #step_module=re.sub(r"^\$\{KIPRJMOD\}.*$",last_pcb_path, sm)
- #step_module=re.sub('\${.KIPRJMOD}/', '', step_module)
- step_module=step_module.replace(u'"', u'') # name with spaces
- encoded=1
- say('adjusting Relative Path')
- say('step-module-replaced '+step_module)
+ step_module = step_module.replace("${KIPRJMOD}", last_pcb_path)
+ # sm=step_module
+ # step_module=re.sub(r"^\$\{KIPRJMOD\}.*$",last_pcb_path, sm)
+ # step_module=re.sub('\${.KIPRJMOD}/', '', step_module)
+ step_module = step_module.replace('"', "") # name with spaces
+ encoded = 1
+ say("adjusting Relative Path")
+ say("step-module-replaced " + step_module)
# elif (step_module.startswith('.')) or (step_module.startswith('".')): #relative path
# #step_module=last_pcb_path+"/"+step_module
# step_module=last_pcb_path+os.sep+step_module
@@ -4621,427 +4947,471 @@ def Load_models(pcbThickness,modules):
# sayw('adjusting Relative Path')
# say('step-module-replaced '+step_module)
# #stop
- elif (step_module.find('${KISYS3DMOD}/')!=-1): #local ${KISYS3DMOD} 3D path
- #step_module=step_module.replace('${KIPRJMOD}', '.')
- #step_module=step_module.decode("utf-8").replace(u'${KISYS3DMOD}/', u'')
- step_module=step_module.replace(u'${KISYS3DMOD}/', u'')
- step_module=step_module.replace(u'"', u'') # name with spaces
- #step_module=last_pcb_path+step_module[14:]
- encoded=1
- say('adjusting Local Path')
- say('step-module-replaced '+step_module)
- elif (step_module.find('${')!=-1) and encoded==0: #extra local ${ENV} 3D path
- step_module= re.sub('\${.*?}/', '', step_module)
- #step_module=step_module.decode("utf-8").replace(u'${}/', u'')
- step_module=step_module.replace(u'${}/', u'')
- step_module=step_module.replace(u'"', u'') # name with spaces
- encoded=1
- say('adjusting 2nd Local Path')
- say('step-module-replaced '+step_module)
- elif (step_module.find('$(')!=-1) and encoded==0: #extra local $(ENV) 3D path
- step_module= re.sub('\$(.*?)/', '', step_module)
- #step_module=step_module.decode("utf-8").replace(u'${}/', u'')
- step_module=step_module.replace(u'$()/', u'')
- step_module=step_module.replace(u'"', u'') # name with spaces
- encoded=1
- say('adjusting 2nd Local Path')
- say('step-module-replaced '+step_module)
- if (encoded == 0) and step_module != 'no3Dmodel' and modules[i][4] != 'noLayer': #test local 3D path without the use of KIPRJMOD or ENV
- step_module_local = re.sub("\\\\", "/", step_module) #subst '\\' with '/'
+ elif step_module.find("${KISYS3DMOD}/") != -1: # local ${KISYS3DMOD} 3D path
+ # step_module=step_module.replace('${KIPRJMOD}', '.')
+ # step_module=step_module.decode("utf-8").replace(u'${KISYS3DMOD}/', u'')
+ step_module = step_module.replace("${KISYS3DMOD}/", "")
+ step_module = step_module.replace('"', "") # name with spaces
+ # step_module=last_pcb_path+step_module[14:]
+ encoded = 1
+ say("adjusting Local Path")
+ say("step-module-replaced " + step_module)
+ elif (step_module.find("${") != -1) and encoded == 0: # extra local ${ENV} 3D path
+ step_module = re.sub(r"\${.*?}/", "", step_module)
+ # step_module=step_module.decode("utf-8").replace(u'${}/', u'')
+ step_module = step_module.replace("${}/", "")
+ step_module = step_module.replace('"', "") # name with spaces
+ encoded = 1
+ say("adjusting 2nd Local Path")
+ say("step-module-replaced " + step_module)
+ elif (step_module.find("$(") != -1) and encoded == 0: # extra local $(ENV) 3D path
+ step_module = re.sub(r"\$(.*?)/", "", step_module)
+ # step_module=step_module.decode("utf-8").replace(u'${}/', u'')
+ step_module = step_module.replace("$()/", "")
+ step_module = step_module.replace('"', "") # name with spaces
+ encoded = 1
+ say("adjusting 2nd Local Path")
+ say("step-module-replaced " + step_module)
+ if (
+ (encoded == 0) and step_module != "no3Dmodel" and modules[i][4] != "noLayer"
+ ): # test local 3D path without the use of KIPRJMOD or ENV
+ step_module_local = re.sub("\\\\", "/", step_module) # subst '\\' with '/'
# step_module_local = step_module_local.replace("\\", "/") #subst '\' with '/'
last_pcb_path_local = re.sub("\\\\", "/", last_pcb_path)
# print(step_module)
# print(step_module_local)
- step_module_local=step_module_local.replace(u'"', u'') # name with spaces
- #print(step_module_local)
- utf_path_local=os.path.join(make_unicode(last_pcb_path_local),make_unicode(step_module_local))
- #print(utf_path_local)
- pos=utf_path_local.rfind('.')
- #sayw(pos)
- rel_pos=len(utf_path_local)-pos
- local_path=utf_path_local[:-rel_pos+1]
- #print(local_path)
- #stop
- if os.path.exists(local_path+u'stpZ'):
- step_module = local_path+u'stpZ'
- encoded=1
- say('adjusting Relative Path to pcb file')
- say('step-module-replaced '+step_module)
- elif os.path.exists(local_path+u'stpz'):
- step_module = local_path+u'stpz'
- encoded=1
- say('adjusting Relative Path to pcb file')
- say('step-module-replaced '+step_module)
- elif os.path.exists(local_path+u'STPZ'):
- step_module = local_path+u'STPZ'
- encoded=1
- say('adjusting Relative Path to pcb file')
- say('step-module-replaced '+step_module)
- elif os.path.exists(local_path+u'step'):
- step_module = local_path+u'step'
- encoded=1
- say('adjusting Relative Path to pcb file')
- say('step-module-replaced '+step_module)
- elif os.path.exists(local_path+u'STEP'):
- step_module = local_path+u'STEP'
- encoded=1
- say('adjusting Relative Path to pcb file')
- say('step-module-replaced '+step_module)
- elif os.path.exists(local_path+u'stp'):
- step_module = local_path+u'stp'
- encoded=1
- say('adjusting Relative Path to pcb file')
- say('step-module-replaced '+step_module)
- elif os.path.exists(local_path+u'STP'):
- step_module = local_path+u'STP'
- encoded=1
- say('adjusting Relative Path to pcb file')
- say('step-module-replaced '+step_module)
-
- elif os.path.exists(local_path+u'iges'):
- step_module = local_path+u'iges'
- encoded=1
- say('adjusting Relative Path to pcb file')
- say('step-module-replaced '+step_module)
- elif os.path.exists(local_path+u'IGES'):
- step_module = local_path+u'IGES'
- encoded=1
- say('adjusting Relative Path to pcb file')
- say('step-module-replaced '+step_module)
- elif os.path.exists(local_path+u'igs'):
- step_module = local_path+u'igs'
- encoded=1
- say('adjusting Relative Path to pcb file')
- say('step-module-replaced '+step_module)
- elif os.path.exists(local_path+u'IGS'):
- step_module = local_path+u'IGS'
- encoded=1
- say('adjusting Relative Path to pcb file')
- say('step-module-replaced '+step_module)
+ step_module_local = step_module_local.replace('"', "") # name with spaces
+ # print(step_module_local)
+ utf_path_local = os.path.join(make_unicode(last_pcb_path_local), make_unicode(step_module_local))
+ # print(utf_path_local)
+ pos = utf_path_local.rfind(".")
+ # sayw(pos)
+ rel_pos = len(utf_path_local) - pos
+ local_path = utf_path_local[: -rel_pos + 1]
+ # print(local_path)
+ # stop
+ if os.path.exists(local_path + "stpZ"):
+ step_module = local_path + "stpZ"
+ encoded = 1
+ say("adjusting Relative Path to pcb file")
+ say("step-module-replaced " + step_module)
+ elif os.path.exists(local_path + "stpz"):
+ step_module = local_path + "stpz"
+ encoded = 1
+ say("adjusting Relative Path to pcb file")
+ say("step-module-replaced " + step_module)
+ elif os.path.exists(local_path + "STPZ"):
+ step_module = local_path + "STPZ"
+ encoded = 1
+ say("adjusting Relative Path to pcb file")
+ say("step-module-replaced " + step_module)
+ elif os.path.exists(local_path + "step"):
+ step_module = local_path + "step"
+ encoded = 1
+ say("adjusting Relative Path to pcb file")
+ say("step-module-replaced " + step_module)
+ elif os.path.exists(local_path + "STEP"):
+ step_module = local_path + "STEP"
+ encoded = 1
+ say("adjusting Relative Path to pcb file")
+ say("step-module-replaced " + step_module)
+ elif os.path.exists(local_path + "stp"):
+ step_module = local_path + "stp"
+ encoded = 1
+ say("adjusting Relative Path to pcb file")
+ say("step-module-replaced " + step_module)
+ elif os.path.exists(local_path + "STP"):
+ step_module = local_path + "STP"
+ encoded = 1
+ say("adjusting Relative Path to pcb file")
+ say("step-module-replaced " + step_module)
+
+ elif os.path.exists(local_path + "iges"):
+ step_module = local_path + "iges"
+ encoded = 1
+ say("adjusting Relative Path to pcb file")
+ say("step-module-replaced " + step_module)
+ elif os.path.exists(local_path + "IGES"):
+ step_module = local_path + "IGES"
+ encoded = 1
+ say("adjusting Relative Path to pcb file")
+ say("step-module-replaced " + step_module)
+ elif os.path.exists(local_path + "igs"):
+ step_module = local_path + "igs"
+ encoded = 1
+ say("adjusting Relative Path to pcb file")
+ say("step-module-replaced " + step_module)
+ elif os.path.exists(local_path + "IGS"):
+ step_module = local_path + "IGS"
+ encoded = 1
+ say("adjusting Relative Path to pcb file")
+ say("step-module-replaced " + step_module)
# print(modules[i][4],i,step_module)
# print(modules[i][4] == 'noLayer')
- if step_module != 'no3Dmodel' and modules[i][4] != 'noLayer':
- #model_type = step_module.split('.')[1]
- #if encoded!=1:
- step_module = re.sub("\\\\", "/", step_module) #subst '\\' with '/'
+ if step_module != "no3Dmodel" and modules[i][4] != "noLayer":
+ # model_type = step_module.split('.')[1]
+ # if encoded!=1:
+ step_module = re.sub("\\\\", "/", step_module) # subst '\\' with '/'
# step_module = step_module.replace("\\", "/") #subst '\' with '/'
-
- wrl_model = ''
- if step_module.lower().endswith('wrl') or step_module.lower().endswith('wrz'):
+
+ wrl_model = ""
+ if step_module.lower().endswith("wrl") or step_module.lower().endswith("wrz"):
wrl_model = step_module
- #step_transparency = check_wrl_transparency
- step_module=step_module.replace(u'"', u'') # name with spaces
- pos=step_module.rfind('.')
- #sayw(pos)
- rel_pos=len(step_module)-pos
- #sayw(rel_pos)
- #stop
- step_module=step_module[:-rel_pos+1]+u'stpZ'
- step_module_lw=step_module[:-4]+u'stpz'
- step_module_up=step_module[:-4]+u'STPZ'
- #step_module=step_module[:-3]+'step'
- step_module2=step_module[:-4]+u'step'
- step_module2_up=step_module[:-4]+u'STEP'
- step_module3=step_module[:-4]+u'stp'
- step_module3_up=step_module[:-4]+u'stp'
- step_module4=step_module[:-4]+u'iges'
- step_module4_up=step_module[:-4]+u'IGES'
- step_module5=step_module[:-4]+u'igs'
- step_module5_up=step_module[:-4]+u'IGS'
+ # step_transparency = check_wrl_transparency
+ step_module = step_module.replace('"', "") # name with spaces
+ pos = step_module.rfind(".")
+ # sayw(pos)
+ rel_pos = len(step_module) - pos
+ # sayw(rel_pos)
+ # stop
+ step_module = step_module[: -rel_pos + 1] + "stpZ"
+ step_module_lw = step_module[:-4] + "stpz"
+ step_module_up = step_module[:-4] + "STPZ"
+ # step_module=step_module[:-3]+'step'
+ step_module2 = step_module[:-4] + "step"
+ step_module2_up = step_module[:-4] + "STEP"
+ step_module3 = step_module[:-4] + "stp"
+ step_module3_up = step_module[:-4] + "stp"
+ step_module4 = step_module[:-4] + "iges"
+ step_module4_up = step_module[:-4] + "IGES"
+ step_module5 = step_module[:-4] + "igs"
+ step_module5_up = step_module[:-4] + "IGS"
# step_module=step_module[:-rel_pos+1]+u'step'
# #step_module=step_module[:-3]+'step'
# step_module2=step_module[:-4]+u'stp'
# step_module3=step_module[:-4]+u'iges'
# step_module4=step_module[:-4]+u'igs'
# step_module5=step_module[:-4]+u'stpz'
- #if encoded!=1:
+ # if encoded!=1:
# #step_module=step_module.decode("utf-8").replace(u'"', u'') # name with spaces
# step_module=step_module.replace(u'"', u'') # name with spaces
- model_name=step_module[:-5]
- last_slash_pos1=model_name.rfind('/')
- last_slash_pos2=model_name.rfind('\\')
- last_slash_pos=max(last_slash_pos1,last_slash_pos2)
- model_name=model_name[last_slash_pos+1:]
- #say('model name '+model_name+'.'+model_type)
- say('model name '+model_name)
+ model_name = step_module[:-5]
+ last_slash_pos1 = model_name.rfind("/")
+ last_slash_pos2 = model_name.rfind("\\")
+ last_slash_pos = max(last_slash_pos1, last_slash_pos2)
+ model_name = model_name[last_slash_pos + 1 :]
+ # say('model name '+model_name+'.'+model_type)
+ say("model name " + model_name)
else:
- model_name='no3Dmodel'
- blacklisted=0
- if blacklisted_model_elements != '':
- if blacklisted_model_elements.find(model_name) != -1:
- if model_name not in whitelisted_3Dmodels:
- blacklisted=1
+ model_name = "no3Dmodel"
+ blacklisted = 0
+ if blacklisted_model_elements != "" and blacklisted_model_elements.find(model_name) != -1:
+ if model_name not in whitelisted_3Dmodels:
+ blacklisted = 1
###
- if (blacklisted==0):
+ if blacklisted == 0:
# print(modules[i][4],i,step_module)
# print(modules[i][4] == 'noLayer')
- if step_module != 'no3Dmodel' and modules[i][4] != 'noLayer':
- createScaledObjs=False
- if model_name=="box_mcad" or model_name=="cylV_mcad" or model_name=="cylH_mcad":
- createScaledObjs=True
+ if step_module != "no3Dmodel" and modules[i][4] != "noLayer":
+ createScaledObjs = False
+ if model_name in {"box_mcad", "cylV_mcad", "cylH_mcad"}:
+ createScaledObjs = True
if not createScaledObjs:
- path_list = [models3D_prefix,models3D_prefix2,models3D_prefix3,models3D_prefix4]
- if default_prefix3d not in path_list:
- if os.path.exists(default_prefix3d):
- path_list.insert(0, default_prefix3d)
- model_type = [step_module,step_module_lw,step_module_up,step_module2,step_module2_up,step_module3,step_module3_up,step_module4,step_module4_up,step_module5,step_module5_up]
- module_path = findModelPath(model_type, path_list) # Find module in all paths and types specified
+ path_list = [models3D_prefix, models3D_prefix2, models3D_prefix3, models3D_prefix4]
+ if default_prefix3d not in path_list and os.path.exists(default_prefix3d):
+ path_list.insert(0, default_prefix3d)
+ model_type = [
+ step_module,
+ step_module_lw,
+ step_module_up,
+ step_module2,
+ step_module2_up,
+ step_module3,
+ step_module3_up,
+ step_module4,
+ step_module4_up,
+ step_module5,
+ step_module5_up,
+ ]
+ module_path = findModelPath(model_type, path_list) # Find module in all paths and types specified
else:
- scale_vrml=modules[i][8]
- #sayw(scale_vrml)
- #scale_val=scale_vrml.split(" ")
- scale_val=scale_vrml
- #sayw(scale_val)
- createScaledBBox(model_name,scale_val)
- module_path='internal shape'
- if module_path!='not-found' and module_path!='internal shape':
- #FreeCADGui.Selection.removeSelection(FreeCAD.activeDocument().ActiveObject) mauitemp volume diff
- say("opening "+ module_path)
- mod_cnt+=1
- doc1=FreeCAD.ActiveDocument
- counterObj=0;counter=0
- prevObjs = doc1.Objects
+ scale_vrml = modules[i][8]
+ # sayw(scale_vrml)
+ # scale_val=scale_vrml.split(" ")
+ scale_val = scale_vrml
+ # sayw(scale_val)
+ createScaledBBox(model_name, scale_val)
+ module_path = "internal shape"
+ if module_path not in {"not-found", "internal shape"}:
+ # FreeCADGui.Selection.removeSelection(FreeCAD.activeDocument().ActiveObject) mauitemp volume diff
+ say("opening " + module_path)
+ mod_cnt += 1
+ doc1 = FreeCAD.ActiveDocument
+ counterObj = 0
+ counter = 0
for ObJ in doc1.Objects:
- counterObj+=1
+ counterObj += 1
say(model_name)
Links_available = False
- if 'LinkView' in dir(FreeCADGui):
+ if "LinkView" in dir(FreeCADGui):
Links_available = True
if model_name not in loaded_models:
loaded_models.append(model_name)
- #sayw(module_path)
- #make_unicode(module_path)
- #module_path_n = re.sub("/", "\\\\", module_path)
- #sayerr(module_path_n)
- #ImportGui.insert(module_path_n,FreeCAD.ActiveDocument.Name)
- try: #tobefixed HERE
+ # sayw(module_path)
+ # make_unicode(module_path)
+ # module_path_n = re.sub("/", "\\\\", module_path)
+ # sayerr(module_path_n)
+ # ImportGui.insert(module_path_n,FreeCAD.ActiveDocument.Name)
+ try: # tobefixed HERE
# support for stpZ files
module_path = re.sub("\\\\", "/", module_path)
module_path = re.sub("//", "/", module_path) ## new maui new!!!
- if module_path.lower().endswith('stpz'):
+ if module_path.lower().endswith("stpz"):
import stepZ
- stepZ.insert(module_path,FreeCAD.ActiveDocument.Name)
- elif module_path.lower().endswith('iges') or module_path.lower().endswith('igs'):
+
+ stepZ.insert(module_path, FreeCAD.ActiveDocument.Name)
+ elif module_path.lower().endswith("iges") or module_path.lower().endswith("igs"):
sayerr("bug for ImportGui *.iges ... using Part.insert")
- Part.insert(module_path,FreeCAD.ActiveDocument.Name)
+ Part.insert(module_path, FreeCAD.ActiveDocument.Name)
else:
- ImportGui.insert(module_path,FreeCAD.ActiveDocument.Name)
+ ImportGui.insert(module_path, FreeCAD.ActiveDocument.Name)
# on FC0.20+ there is an issue in inserting a 'compound'
# FreeCAD.ActiveDocument.ActiveObject.recompute(True)
# say('model imported w ImportGui')
- #FreeCADGui.Selection.clearSelection()
+ # FreeCADGui.Selection.clearSelection()
imported_obj_list = []
- counterTmp=0
+ counterTmp = 0
for ObJ in doc1.Objects:
- counterTmp+=1#stop
- mp_found=False
- if counterTmp!=counterObj+1:
- #multipart loaded
- #print ('allow_compound ',allow_compound)
+ counterTmp += 1 # stop
+ mp_found = False
+ if counterTmp != counterObj + 1:
+ # multipart loaded
+ # print ('allow_compound ',allow_compound)
FreeCADGui.Selection.clearSelection()
- mp_found=True
- #if allow_compound != 'False' and allow_compound != 'Hierarchy':
- if allow_compound != 'False' and (allow_compound != 'Hierarchy' or not Links_available):
- create_compound(counterObj,model_name)
+ mp_found = True
+ # if allow_compound != 'False' and allow_compound != 'Hierarchy':
+ if allow_compound != "False" and (allow_compound != "Hierarchy" or not Links_available):
+ create_compound(counterObj, model_name)
myStep = FreeCAD.ActiveDocument.ActiveObject
impLabel = myStep.Label
- elif allow_compound == 'Hierarchy' and Links_available:
- imported_obj_list = doc1.Objects[counterObj+1:]
- compound_found=True
- #say(str(doc1.Objects)+' HERE')
- #sayw(str(imported_obj_list)+' HERE')
+ elif allow_compound == "Hierarchy" and Links_available:
+ imported_obj_list = doc1.Objects[counterObj + 1 :]
+ compound_found = True
+ # say(str(doc1.Objects)+' HERE')
+ # sayw(str(imported_obj_list)+' HERE')
newStep = find_top_container(imported_obj_list)
if newStep is not None:
impLabel = make_string(newStep.Label)
- else: #old format import multi objs without a Part container
+ else: # old format import multi objs without a Part container
actObjs = doc1.Objects
- actObjNum = len (actObjs)
- newStep = doc1.addObject('App::Part',model_name)
+ len(actObjs)
+ newStep = doc1.addObject("App::Part", model_name)
impLabel = make_string(newStep.Label)
for o in actObjs[counterObj:]:
doc1.getObject(newStep.Name).addObject(doc1.getObject(o.Name))
- #print(o.Label)
- #myStep = FreeCAD.ActiveDocument.ActiveObject
- #print(myStep.Label)
- #impLabel = myStep.Label
- if (allow_compound != 'Hierarchy' or not Links_available) or not mp_found :
- newStep=reset_prop_shapes(FreeCAD.ActiveDocument.ActiveObject,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui,True)
- myStep=newStep
- if wrl_model != '':
- wrl_module_path = module_path[:module_path.rfind(u'.')]+wrl_model[-4:]
+ # print(o.Label)
+ # myStep = FreeCAD.ActiveDocument.ActiveObject
+ # print(myStep.Label)
+ # impLabel = myStep.Label
+ if (allow_compound != "Hierarchy" or not Links_available) or not mp_found:
+ newStep = reset_prop_shapes(
+ FreeCAD.ActiveDocument.ActiveObject,
+ FreeCAD.ActiveDocument,
+ FreeCAD,
+ FreeCADGui,
+ True,
+ )
+ myStep = newStep
+ if wrl_model != "":
+ wrl_module_path = module_path[: module_path.rfind(".")] + wrl_model[-4:]
step_transparency = check_wrl_transparency(wrl_module_path)
- if step_transparency != 0: #keeping transparency if found in step file
- FreeCADGui.ActiveDocument.getObject(myStep.Name).Transparency = step_transparency
+ if step_transparency != 0: # keeping transparency if found in step file
+ FreeCADGui.ActiveDocument.getObject(
+ myStep.Name,
+ ).Transparency = step_transparency
impLabel = make_string(myStep.Label)
- #use_pypro=False
- if use_pypro: #use python property for timestamp
- myObj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","model3D")
- myObj.ViewObject.Proxy = 0 # this is mandatory unless we code the ViewProvider too
+ # use_pypro=False
+ if use_pypro: # use python property for timestamp
+ myObj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "model3D")
+ myObj.ViewObject.Proxy = 0 # this is mandatory unless we code the ViewProvider too
myObj.Shape = newStep.Shape
- newStep.Label = 'old'
- #myObj.Label = impLabel
- #print(modules[i][10]);print(modules[i][11])
- myObj.addProperty("App::PropertyString","TimeStamp")
- myObj.TimeStamp=str(modules[i][10])
- myObj.addProperty("App::PropertyString","Reference")
- myObj.Reference=str(modules[i][11])
- if '*' not in myObj.Reference:
- myObj.Label = myObj.Reference + '_'+ impLabel
+ newStep.Label = "old"
+ # myObj.Label = impLabel
+ # print(modules[i][10]);print(modules[i][11])
+ myObj.addProperty("App::PropertyString", "TimeStamp")
+ myObj.TimeStamp = str(modules[i][10])
+ myObj.addProperty("App::PropertyString", "Reference")
+ myObj.Reference = str(modules[i][11])
+ if "*" not in myObj.Reference:
+ myObj.Label = myObj.Reference + "_" + impLabel
else:
- myObj.Label = 'REF_'+impLabel + '_'
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(newStep.Name).ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(newStep.Name).LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(newStep.Name).PointColor
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(newStep.Name).DiffuseColor
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(newStep.Name).Transparency
+ myObj.Label = "REF_" + impLabel + "_"
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(
+ newStep.Name,
+ ).ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(
+ newStep.Name,
+ ).LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(
+ newStep.Name,
+ ).PointColor
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = (
+ FreeCADGui.ActiveDocument.getObject(newStep.Name).DiffuseColor
+ )
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = (
+ FreeCADGui.ActiveDocument.getObject(newStep.Name).Transparency
+ )
FreeCAD.ActiveDocument.removeObject(newStep.Name)
- else: #use Label for timestamp
- myReference=str(modules[i][11]).rstrip('"').lstrip('"')
- myTimeStamp=str(modules[i][10]).rstrip('"').lstrip('"')
- if len(myTimeStamp)> 8:
- myTimeStamp=myTimeStamp[-12:]
- myModelNbr=(modules[i][12])
- #print (myModelNbr)#;stop
- if myModelNbr == 1:
- myModelNbr = ''
- else:
- myModelNbr = '['+str(myModelNbr)+']'
- if '*' not in myReference:
- newStep.Label = myReference + '_'+ impLabel + '_' + myTimeStamp + myModelNbr
+ else: # use Label for timestamp
+ myReference = str(modules[i][11]).rstrip('"').lstrip('"')
+ myTimeStamp = str(modules[i][10]).rstrip('"').lstrip('"')
+ if len(myTimeStamp) > 8:
+ myTimeStamp = myTimeStamp[-12:]
+ myModelNbr = modules[i][12]
+ # print (myModelNbr)#;stop
+ myModelNbr = "" if myModelNbr == 1 else "[" + str(myModelNbr) + "]"
+ if "*" not in myReference:
+ newStep.Label = myReference + "_" + impLabel + "_" + myTimeStamp + myModelNbr
else:
- newStep.Label = 'REF_'+impLabel + '_' + myTimeStamp + myModelNbr
- #stop
- #sayerr('loading first time!!!')
- counterTmp=0
+ newStep.Label = "REF_" + impLabel + "_" + myTimeStamp + myModelNbr
+ # stop
+ # sayerr('loading first time!!!')
+ counterTmp = 0
for ObJ in doc1.Objects:
- counterTmp+=1#stop
- #sayw(str(counterObj)+":"+str(counterTmp))
- #stop
- if counterTmp==counterObj:
- #bug in ImportGui.insert iges file
+ counterTmp += 1 # stop
+ # sayw(str(counterObj)+":"+str(counterTmp))
+ # stop
+ if counterTmp == counterObj:
+ # bug in ImportGui.insert iges file
sayerr("bug for ImportGui *.iges ... using Part.insert")
- Part.insert(module_path,FreeCAD.ActiveDocument.Name)
+ Part.insert(module_path, FreeCAD.ActiveDocument.Name)
# s = Part.Shape()
# s.read(module_path) # incoming file igs, stp, stl, brep NO colors!
# Part.show(s)
- #Part.Shape.read(module_path)
- #Part.insert(module_path,FreeCAD.ActiveDocument.Name)
- except: #tobefixed
- sayerr('3D STEP model '+model_name+' is WRONG')
- msg="""3D STEP model """
- msg+=model_name+" is WRONG
or are not allowed Multi Part objects...
"
- msg+="@ "+module_path+"
...stopping execution!
Please fix the model or change your settings."
+ # Part.Shape.read(module_path)
+ # Part.insert(module_path,FreeCAD.ActiveDocument.Name)
+ except: # tobefixed
+ sayerr("3D STEP model " + model_name + " is WRONG")
+ msg = """3D STEP model """
+ msg += model_name + " is WRONG
or are not allowed Multi Part objects...
"
+ msg += (
+ "@ "
+ + module_path
+ + "
...stopping execution!
Please fix the model or change your settings."
+ )
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Info ...",msg)
- stop
- if allow_compound != 'False' and (allow_compound != 'Hierarchy' or not Links_available):
- create_compound(counterObj,model_name)
+ QtGui.QMessageBox.information(None, "Info ...", msg)
+ stop
+ if allow_compound != "False" and (allow_compound != "Hierarchy" or not Links_available):
+ create_compound(counterObj, model_name)
newobj = FreeCAD.ActiveDocument.ActiveObject
if not use_pypro:
- if '*' not in myReference:
- newobj.Label = myReference + '_'+ impLabel + '_' + myTimeStamp + myModelNbr
+ if "*" not in myReference:
+ newobj.Label = myReference + "_" + impLabel + "_" + myTimeStamp + myModelNbr
else:
- newobj.Label = 'REF_'+impLabel + '_' + myTimeStamp + myModelNbr
+ newobj.Label = "REF_" + impLabel + "_" + myTimeStamp + myModelNbr
##addProperty mod
- #newobj=reset_prop_shapes(FreeCAD.ActiveDocument.ActiveObject,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
- elif allow_compound == 'Hierarchy' and mp_found:
+ # newobj=reset_prop_shapes(FreeCAD.ActiveDocument.ActiveObject,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
+ elif allow_compound == "Hierarchy" and mp_found:
newobj = newStep
- #tobefixed
+ # tobefixed
if not use_pypro:
- if '*' not in myReference:
- newobj.Label = myReference + '_'+ impLabel + '_' + myTimeStamp + myModelNbr
+ if "*" not in myReference:
+ newobj.Label = myReference + "_" + impLabel + "_" + myTimeStamp + myModelNbr
else:
- newobj.Label = 'REF_'+impLabel + '_' + myTimeStamp + myModelNbr
+ newobj.Label = "REF_" + impLabel + "_" + myTimeStamp + myModelNbr
else:
- newobj = FreeCAD.ActiveDocument.ActiveObject ##addProperty mod
- #newobj=reset_prop_shapes(FreeCAD.ActiveDocument.ActiveObject,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
- #newobj = FreeCAD.ActiveDocument.ActiveObject
- #stop
+ newobj = FreeCAD.ActiveDocument.ActiveObject ##addProperty mod
+ # newobj=reset_prop_shapes(FreeCAD.ActiveDocument.ActiveObject,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
+ # newobj = FreeCAD.ActiveDocument.ActiveObject
+ # stop
##newobj.Label=newobj.Label+"_"
# not adding '_' at the end of the name
- if (bbox_all==1) or (bbox_list==1):
+ if (bbox_all == 1) or (bbox_list == 1):
if whitelisted_model_elements.find(model_name) == -1:
- bboxLabel=newobj.Label=newobj.Label
- newobj=createSolidBBox3(newobj)
- skip_status="not"
- #tobefixed volume for App::Part
+ newobj.Label = newobj.Label
+ newobj = createSolidBBox3(newobj)
+ skip_status = "not"
+ # tobefixed volume for App::Part
if model_name not in whitelisted_3Dmodels:
- if volume_minimum != 0 or height_minimum != 0: #if checking volume or height
- if newobj.Shape.Volume>volume_minimum: #mauitemp min vol
- if abs(newobj.Shape.BoundBox.ZLength)>height_minimum: #mauitemp min height
- if (height_minimum!=0):
- say("height > Min height "+ str(newobj.Shape.BoundBox.ZLength) + " "+newobj.Label)
- if (volume_minimum!=0):
- say("Volume > Min Volume "+ str(newobj.Shape.Volume) + " "+newobj.Label)
+ if volume_minimum != 0 or height_minimum != 0: # if checking volume or height
+ if newobj.Shape.Volume > volume_minimum: # mauitemp min vol
+ if abs(newobj.Shape.BoundBox.ZLength) > height_minimum: # mauitemp min height
+ if height_minimum != 0:
+ say(
+ "height > Min height "
+ + str(newobj.Shape.BoundBox.ZLength)
+ + " "
+ + newobj.Label,
+ )
+ if volume_minimum != 0:
+ say("Volume > Min Volume " + str(newobj.Shape.Volume) + " " + newobj.Label)
else:
- skip_status="skip"
- say("height <= Min height "+ str(newobj.Shape.BoundBox.ZLength) + " "+newobj.Label)
+ skip_status = "skip"
+ say(
+ "height <= Min height "
+ + str(newobj.Shape.BoundBox.ZLength)
+ + " "
+ + newobj.Label,
+ )
else:
- skip_status="skip"
- say("Volume <= Min Volume "+ str(newobj.Shape.BoundBox.ZLength) + " "+newobj.Label)
+ skip_status = "skip"
+ say(
+ "Volume <= Min Volume "
+ + str(newobj.Shape.BoundBox.ZLength)
+ + " "
+ + newobj.Label,
+ )
loaded_models_skipped.append(skip_status)
- use_cache=0
- #say("NO use_cache")
+ use_cache = 0
+ # say("NO use_cache")
FreeCADGui.Selection.clearSelection()
for ObJ in doc1.Objects:
- counter+=1
- if counterObj+1 != counter and (allow_compound != 'Hierarchy' or not Links_available):
- msg="""3D STEP model """
- msg+=model_name+" is NOT fused ('union') in a single part ...
"
- msg+="@ "+module_path+"
...stopping execution!
Please fix the model."
+ counter += 1
+ if counterObj + 1 != counter and (allow_compound != "Hierarchy" or not Links_available):
+ msg = """3D STEP model """
+ msg += model_name + " is NOT fused ('union') in a single part ...
"
+ msg += "@ " + module_path + "
...stopping execution!
Please fix the model."
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Info ...",msg)
+ QtGui.QMessageBox.information(None, "Info ...", msg)
stop
- if skip_status!="skip":
+ if skip_status != "skip":
loaded_model_objs.append(newobj)
else:
loaded_model_objs.append(None)
FreeCAD.activeDocument().removeObject(newobj.Name)
else:
- use_cache=1
- #sayw("using cache!!!")
- #say(loaded_models);say(" models")
- #say(str(len(loaded_model_objs))+" nbr loaded objs")
+ use_cache = 1
+ # sayw("using cache!!!")
+ # say(loaded_models);say(" models")
+ # say(str(len(loaded_model_objs))+" nbr loaded objs")
if use_cache:
- counterObj=counterObj-2
- pos_x=modules[i][1]-off_x
- pos_y=modules[i][2]-off_y
- rot=modules[i][3]
- step_layer=modules[i][4]
- #wrl_off_x=modules[i][6]
- #rotz_vrml_norm=modules[i][7][0].replace("(xyz ","")
- #rotz_vrml_norm=modules[i][7].replace("(xyz ","")
- #say("rotz_vrml_norm ");sayw(rotz_vrml_norm)
- wrl_rot=modules[i][7]
- #sayerr(wrl_rot);sayw(float(wrl_rot[0]));stop
- pos_vrml=modules[i][6]
- wrl_pos=pos_vrml
- #sayerr(wrl_pos);sayw(float(wrl_pos[0]));stop
- isVirtual=modules[i][9]
- isHidden=modules[i][13]
- if (isHidden):
- md_hide=True
- else:
- md_hide=False
-
- #if show_debug:
+ counterObj = counterObj - 2
+ pos_x = modules[i][1] - off_x
+ pos_y = modules[i][2] - off_y
+ rot = modules[i][3]
+ step_layer = modules[i][4]
+ # wrl_off_x=modules[i][6]
+ # rotz_vrml_norm=modules[i][7][0].replace("(xyz ","")
+ # rotz_vrml_norm=modules[i][7].replace("(xyz ","")
+ # say("rotz_vrml_norm ");sayw(rotz_vrml_norm)
+ wrl_rot = modules[i][7]
+ # sayerr(wrl_rot);sayw(float(wrl_rot[0]));stop
+ pos_vrml = modules[i][6]
+ wrl_pos = pos_vrml
+ # sayerr(wrl_pos);sayw(float(wrl_pos[0]));stop
+ isVirtual = modules[i][9]
+ isHidden = modules[i][13]
+ md_hide = bool(isHidden)
+
+ # if show_debug:
# sayw(wrl_rot)
# sayerr(modules[i])
- #wrl_pos=pos_vrml[0].split(" ")
- #wrl_pos=pos_vrml.split(" ")
- #say(rotz_vrml_norm)
- #sayw("wrl rot ");sayw(wrl_rot)
- #say("wrl pos ");sayw(wrl_pos)
- #say (str(rot))
+ # wrl_pos=pos_vrml[0].split(" ")
+ # wrl_pos=pos_vrml.split(" ")
+ # say(rotz_vrml_norm)
+ # sayw("wrl rot ");sayw(wrl_rot)
+ # say("wrl pos ");sayw(wrl_pos)
+ # say (str(rot))
for j in range(len(loaded_models)):
- if loaded_models[j]==model_name:
- #say (str(i)+" i")
- idxO=j
- if loaded_models_skipped[idxO]!="skip":
+ if loaded_models[j] == model_name:
+ # say (str(i)+" i")
+ idxO = j
+ if loaded_models_skipped[idxO] != "skip":
if use_cache:
- #mod_cnt+=1
- sayw('copying from cache')
+ # mod_cnt+=1
+ sayw("copying from cache")
##impPart=copy_objs(loaded_model_objs[idxO],FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
### FreeCAD.ActiveDocument.addObject('Part::Feature',loaded_model_objs[idxO].Label).Shape=loaded_model_objs[idxO].Shape
### #FreeCAD.ActiveDocument.ActiveObject.Label=obj.Label
@@ -5050,120 +5420,151 @@ def Load_models(pcbThickness,modules):
### FreeCADGui.ActiveDocument.ActiveObject.PointColor=Gui.ActiveDocument.getObject(loaded_model_objs[idxO].Name).PointColor
### FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=Gui.ActiveDocument.getObject(loaded_model_objs[idxO].Name).DiffuseColor
### FreeCAD.ActiveDocument.recompute()
- try: # Links ATM don't support added proprierties
- if use_Links and links_imp_mode == 'links_allowed':
+ try: # Links ATM don't support added proprierties
+ if use_Links and links_imp_mode == "links_allowed":
o = loaded_model_objs[idxO]
# FreeCAD.ActiveDocument.addObject('App::Link',o.Label+'_ln_').setLink(o)
if use_pypro:
- FreeCAD.ActiveDocument.addObject('App::LinkPython',o.Label).setLink(o)
- FreeCAD.ActiveDocument.ActiveObject.addProperty("App::PropertyString","TimeStamp")
- #FreeCAD.ActiveDocument.ActiveObject.TimeStamp=str(modules[i][10])
- FreeCAD.ActiveDocument.ActiveObject.addProperty("App::PropertyString","Reference")
- #FreeCAD.ActiveDocument.ActiveObject.Reference=str(modules[i][11])
+ FreeCAD.ActiveDocument.addObject("App::LinkPython", o.Label).setLink(o)
+ FreeCAD.ActiveDocument.ActiveObject.addProperty(
+ "App::PropertyString",
+ "TimeStamp",
+ )
+ # FreeCAD.ActiveDocument.ActiveObject.TimeStamp=str(modules[i][10])
+ FreeCAD.ActiveDocument.ActiveObject.addProperty(
+ "App::PropertyString",
+ "Reference",
+ )
+ # FreeCAD.ActiveDocument.ActiveObject.Reference=str(modules[i][11])
FreeCAD.ActiveDocument.ActiveObject.ViewObject.Proxy = 0
else:
- FreeCAD.ActiveDocument.addObject('App::Link',o.Label+'_ln_').setLink(o)
+ FreeCAD.ActiveDocument.addObject("App::Link", o.Label + "_ln_").setLink(o)
else:
FreeCAD.ActiveDocument.copyObject(loaded_model_objs[idxO], True)
- #allow_compound != 'Hierarchy':
- impPart=FreeCAD.ActiveDocument.ActiveObject
+ # allow_compound != 'Hierarchy':
+ impPart = FreeCAD.ActiveDocument.ActiveObject
if use_pypro:
- impPart.TimeStamp=str(modules[i][10])
- impPart.Reference=str(modules[i][11])
- if '*' not in impPart.Reference:
- impPart.Label = loaded_model_objs[idxO].Label[loaded_model_objs[idxO].Label.find('_')+1:]
- impPart.Label = impPart.Reference + '_' + impPart.Label # loaded_model_objs[idxO].Label
- #impPart.Label = impPart.Reference + '_'+ impLabel
- #say("FC 0.15 copy method for preserving color in fusion")
+ impPart.TimeStamp = str(modules[i][10])
+ impPart.Reference = str(modules[i][11])
+ if "*" not in impPart.Reference:
+ impPart.Label = loaded_model_objs[idxO].Label[
+ loaded_model_objs[idxO].Label.find("_") + 1 :
+ ]
+ impPart.Label = (
+ impPart.Reference + "_" + impPart.Label
+ ) # loaded_model_objs[idxO].Label
+ # impPart.Label = impPart.Reference + '_'+ impLabel
+ # say("FC 0.15 copy method for preserving color in fusion")
else:
- impPart.Label = 'REF_'+loaded_model_objs[idxO].Label + '_' + myTimeStamp
+ impPart.Label = "REF_" + loaded_model_objs[idxO].Label + "_" + myTimeStamp
else:
- myTimeStamp=str(modules[i][10]).rstrip('"').lstrip('"')
- if len(myTimeStamp)> 8:
- myTimeStamp=myTimeStamp[-12:]
- myReference=str(modules[i][11]).rstrip('"').lstrip('"')
- myModelNbr=(modules[i][12])
- #print (myModelNbr);stop
- if myModelNbr == 1:
- myModelNbr = ''
- else:
- myModelNbr = '['+str(myModelNbr)+']'
- if '*' not in myReference:
- impPart.Label = loaded_model_objs[idxO].Label[loaded_model_objs[idxO].Label.find('_')+1:loaded_model_objs[idxO].Label.rfind('_')]
- impPart.Label = myReference + '_' + impPart.Label + '_' + myTimeStamp + myModelNbr
+ myTimeStamp = str(modules[i][10]).rstrip('"').lstrip('"')
+ if len(myTimeStamp) > 8:
+ myTimeStamp = myTimeStamp[-12:]
+ myReference = str(modules[i][11]).rstrip('"').lstrip('"')
+ myModelNbr = modules[i][12]
+ # print (myModelNbr);stop
+ myModelNbr = "" if myModelNbr == 1 else "[" + str(myModelNbr) + "]"
+ if "*" not in myReference:
+ impPart.Label = loaded_model_objs[idxO].Label[
+ loaded_model_objs[idxO].Label.find("_") + 1 : loaded_model_objs[
+ idxO
+ ].Label.rfind("_")
+ ]
+ impPart.Label = (
+ myReference + "_" + impPart.Label + "_" + myTimeStamp + myModelNbr
+ )
# loaded_model_objs[idxO].Label
else:
- impPart.Label = 'REF_'+loaded_model_objs[idxO].Label[:loaded_model_objs[idxO].Label.rfind('_')] + '_' + myTimeStamp + myModelNbr
+ impPart.Label = (
+ "REF_"
+ + loaded_model_objs[idxO].Label[: loaded_model_objs[idxO].Label.rfind("_")]
+ + "_"
+ + myTimeStamp
+ + myModelNbr
+ )
except:
- #impPart=copy_objs(loaded_model_objs[idxO],FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
- impPart=copy_objs(loaded_model_objs[idxO],FreeCAD.ActiveDocument)
+ # impPart=copy_objs(loaded_model_objs[idxO],FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
+ impPart = copy_objs(loaded_model_objs[idxO], FreeCAD.ActiveDocument)
sayw("fusion color problem in FC earlier than 0.15\n")
- pass
##
- #impPart=reset_prop_shapes2(impPart,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
+ # impPart=reset_prop_shapes2(impPart,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
##resetting placement properties
- impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x,pos_y,-pcbThickness),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
- #obj.Placement = impPart.Placement
- if use_Links and links_imp_mode == 'links_allowed':
- shape=Part.getShape(o)
+ impPart.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(pos_x, pos_y, -pcbThickness),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 1, 0), 180),
+ )
+ # obj.Placement = impPart.Placement
+ if use_Links and links_imp_mode == "links_allowed":
+ shape = Part.getShape(o)
else:
- shape=impPart.Shape.copy()
- shape.Placement=impPart.Placement;
- shape.rotate((pos_x,pos_y,0),(0,0,1),rot)
- impPart.Placement=shape.Placement
- #impPart.Label = impPart.Label + '_ch_'
- #sayerr('caching')
+ shape = impPart.Shape.copy()
+ shape.Placement = impPart.Placement
+ shape.rotate((pos_x, pos_y, 0), (0, 0, 1), rot)
+ impPart.Placement = shape.Placement
+ # impPart.Label = impPart.Label + '_ch_'
+ # sayerr('caching')
else:
- impPart=loaded_model_objs[idxO]
- #impPart.Label = impPart.Label + '_nc_'
+ impPart = loaded_model_objs[idxO]
+ # impPart.Label = impPart.Label + '_nc_'
## say(loaded_model_objs)
- say("module "+step_module)
- #say("selection 3D model "+ impPart.Label)
- #to verify!!!! next row
- ##impPart=reset_prop_shapes(impPart,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
- model3D=impPart.Name
- #say("impPart "+ impPart.Name)
+ say("module " + step_module)
+ # say("selection 3D model "+ impPart.Label)
+ # to verify!!!! next row
+ ##impPart=reset_prop_shapes(impPart,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
+ model3D = impPart.Name
+ # say("impPart "+ impPart.Name)
obj = FreeCAD.ActiveDocument.getObject(model3D)
FreeCADGui.Selection.addSelection(obj)
# obj=FreeCAD.ActiveDocument.ActiveObject # issue for Part containers
- #volume_minimum=1
- myPart=FreeCAD.ActiveDocument.getObject(obj.Name) #mauitemp min vol
+ # volume_minimum=1
+ myPart = FreeCAD.ActiveDocument.getObject(obj.Name) # mauitemp min vol
if md_hide:
- myPart.ViewObject.Visibility=False
+ myPart.ViewObject.Visibility = False
# myPart.ViewObject.Transparency=70
- sayerr('hiding '+myPart.Label)
- my_hide_list+=myPart.Label+'\r\n'
- #else:
+ sayerr("hiding " + myPart.Label)
+ my_hide_list += myPart.Label + "\r\n"
+ # else:
# myPart.ViewObject.Transparency=0
- # sayerr('hiding '+myPart.Label)
- #sayw(obj.Label)
- #sayw(step_layer);
- #sayw(str(myPart.Shape.Volume))
- #sayw(str(myPart.Shape.BoundBox.ZLength))
- if step_layer == 'Top':
+ # sayerr('hiding '+myPart.Label)
+ # sayw(obj.Label)
+ # sayw(step_layer);
+ # sayw(str(myPart.Shape.Volume))
+ # sayw(str(myPart.Shape.BoundBox.ZLength))
+ if step_layer == "Top":
if full_placement:
## new placement wip
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0]),pos_y+float(wrl_pos[1]),0+float(wrl_pos[2])),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),rot))
- # (yaw z, pitch y, roll x)
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,0+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1]),-float(wrl_rot[0])))
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0]),pos_y+float(wrl_pos[1]),0+float(wrl_pos[2])),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),rot))
+ # (yaw z, pitch y, roll x)
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,0+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1]),-float(wrl_rot[0])))
##impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,0+float(wrl_pos[2])*25.4),FreeCAD.Rotation(rot,-float(wrl_rot[1]),-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
- #say("rot z top ");sayw(wrl_rot);sayw(rot)
- impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,0+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1]),-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
- if impPart.TypeId=='App::Link' or impPart.TypeId=='App::LinkPython':
- shape=Part.getShape(o)
- elif impPart.TypeId=='App::Part': #tobefixed
- shape=Part.getShape(impPart)
+ # say("rot z top ");sayw(wrl_rot);sayw(rot)
+ impPart.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(
+ pos_x + float(wrl_pos[0]) * 25.4,
+ pos_y + float(wrl_pos[1]) * 25.4,
+ 0 + float(wrl_pos[2]) * 25.4,
+ ),
+ FreeCAD.Rotation(-float(wrl_rot[2]), -float(wrl_rot[1]), -float(wrl_rot[0])),
+ ) # rot is already rot fp -rot wrl
+ if impPart.TypeId in {"App::Link", "App::LinkPython"}:
+ shape = Part.getShape(o)
+ elif impPart.TypeId == "App::Part": # tobefixed
+ shape = Part.getShape(impPart)
else:
- shape=impPart.Shape.copy()
- shape.Placement=impPart.Placement;
- shape.rotate((pos_x,pos_y,0),(0,0,1),rot+float(wrl_rot[2]))
- impPart.Placement=shape.Placement;
+ shape = impPart.Shape.copy()
+ shape.Placement = impPart.Placement
+ shape.rotate((pos_x, pos_y, 0), (0, 0, 1), rot + float(wrl_rot[2]))
+ impPart.Placement = shape.Placement
##TBChecked
if force_transparency:
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=70
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = 70
##TBChecked
else:
- impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x,pos_y,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),rot))
+ impPart.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(pos_x, pos_y, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), rot),
+ )
FreeCADGui.Selection.addSelection(impPart)
## to evaluate to add App::Part hierarchy
# App.activeDocument().Tip = App.activeDocument().addObject('App::Part','Part')
@@ -5171,920 +5572,992 @@ def Load_models(pcbThickness,modules):
# Gui.activeView().setActiveObject('part', App.activeDocument().Part)
# App.ActiveDocument.recompute()
if isVirtual == 0:
- if use_AppPart and not use_LinkGroups: #layer Top
+ if use_AppPart and not use_LinkGroups: # layer Top
FreeCAD.ActiveDocument.getObject(top_name).addObject(impPart)
- modelTop_nbr+=1
+ modelTop_nbr += 1
elif use_LinkGroups:
- #FreeCAD.ActiveDocument.getObject(impPart.Name).adjustRelativeLinks(FreeCAD.ActiveDocument.getObject('Top'))
- FreeCAD.ActiveDocument.getObject(top_name).ViewObject.dropObject(FreeCAD.ActiveDocument.getObject(impPart.Name),FreeCAD.ActiveDocument.getObject(impPart.Name),'',[])
- modelTop_nbr+=1
+ # FreeCAD.ActiveDocument.getObject(impPart.Name).adjustRelativeLinks(FreeCAD.ActiveDocument.getObject('Top'))
+ FreeCAD.ActiveDocument.getObject(top_name).ViewObject.dropObject(
+ FreeCAD.ActiveDocument.getObject(impPart.Name),
+ FreeCAD.ActiveDocument.getObject(impPart.Name),
+ "",
+ [],
+ )
+ modelTop_nbr += 1
else:
FreeCAD.ActiveDocument.getObject(stepM_name).addObject(impPart)
- else: #virtual
- if use_AppPart and not use_LinkGroups: #layer Top
- #print(topV_name)
+ else: # virtual
+ if use_AppPart and not use_LinkGroups: # layer Top
+ # print(topV_name)
FreeCAD.ActiveDocument.getObject(topV_name).addObject(impPart)
- virtualTop_nbr+=1
+ virtualTop_nbr += 1
elif use_LinkGroups:
- #FreeCAD.ActiveDocument.getObject(impPart.Name).adjustRelativeLinks(FreeCAD.ActiveDocument.getObject('TopV'))
- FreeCAD.ActiveDocument.getObject(topV_name).ViewObject.dropObject(FreeCAD.ActiveDocument.getObject(impPart.Name),FreeCAD.ActiveDocument.getObject(impPart.Name),'',[])
- virtualTop_nbr+=1
+ # FreeCAD.ActiveDocument.getObject(impPart.Name).adjustRelativeLinks(FreeCAD.ActiveDocument.getObject('TopV'))
+ FreeCAD.ActiveDocument.getObject(topV_name).ViewObject.dropObject(
+ FreeCAD.ActiveDocument.getObject(impPart.Name),
+ FreeCAD.ActiveDocument.getObject(impPart.Name),
+ "",
+ [],
+ )
+ virtualTop_nbr += 1
else:
FreeCAD.ActiveDocument.getObject(stepV_name).addObject(impPart)
- virtual_nbr+=1
+ virtual_nbr += 1
###
else:
- #Bottom
- #Bottom
- #impPart=reset_prop_shapes2(impPart,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
+ # Bottom
+ # Bottom
+ # impPart=reset_prop_shapes2(impPart,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
if full_placement:
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x,pos_y,-pcbThickness),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x,pos_y,-pcbThickness),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
## new placement wip
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[1])*25.4,pos_y+float(wrl_pos[0])*25.4,-pcbThickness-float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2])-rot+180,-float(wrl_rot[1])+180,-float(wrl_rot[0])))
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[1])*25.4,pos_y+float(wrl_pos[0])*25.4,-pcbThickness-float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2])-rot+180,-float(wrl_rot[1])+180,-float(wrl_rot[0])))
##impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[1])*25.4,pos_y+float(wrl_pos[0])*25.4,-pcbThickness-float(wrl_pos[2])*25.4),FreeCAD.Rotation(-rot+180,-float(wrl_rot[1])+180,-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
- impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,+pcbThickness+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1]),-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
- if impPart.TypeId=='App::Link' or impPart.TypeId=='App::LinkPython':
- shape=Part.getShape(o)
+ impPart.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(
+ pos_x + float(wrl_pos[0]) * 25.4,
+ pos_y + float(wrl_pos[1]) * 25.4,
+ +pcbThickness + float(wrl_pos[2]) * 25.4,
+ ),
+ FreeCAD.Rotation(-float(wrl_rot[2]), -float(wrl_rot[1]), -float(wrl_rot[0])),
+ ) # rot is already rot fp -rot wrl
+ if impPart.TypeId in {"App::Link", "App::LinkPython"}:
+ shape = Part.getShape(o)
else:
- shape=impPart.Shape.copy()
- shape.Placement=impPart.Placement;
- shape.rotate((pos_x,pos_y,0),(0,0,1),180+rot+float(wrl_rot[2]))
- impPart.Placement=shape.Placement;
- if impPart.TypeId=='App::Link' or impPart.TypeId=='App::LinkPython':
- shape=Part.getShape(o)
+ shape = impPart.Shape.copy()
+ shape.Placement = impPart.Placement
+ shape.rotate((pos_x, pos_y, 0), (0, 0, 1), 180 + rot + float(wrl_rot[2]))
+ impPart.Placement = shape.Placement
+ if impPart.TypeId in {"App::Link", "App::LinkPython"}:
+ shape = Part.getShape(o)
else:
- shape=impPart.Shape.copy()
- shape.Placement=impPart.Placement;
- shape.rotate((pos_x,pos_y,0),(0,1,0),180)
- impPart.Placement=shape.Placement;
+ shape = impPart.Shape.copy()
+ shape.Placement = impPart.Placement
+ shape.rotate((pos_x, pos_y, 0), (0, 1, 0), 180)
+ impPart.Placement = shape.Placement
if force_transparency:
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=60
- #say("rot z bot ");sayw(wrl_rot);sayw(rot)
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,-pcbThickness+float(wrl_pos[2])*25.4),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
+ # say("rot z bot ");sayw(wrl_rot);sayw(rot)
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,-pcbThickness+float(wrl_pos[2])*25.4),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
else:
- impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x,pos_y,-pcbThickness),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
- #obj.Placement = impPart.Placement
- if impPart.TypeId=='App::Link' or impPart.TypeId=='App::LinkPython':
- shape=Part.getShape(o)
+ impPart.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(pos_x, pos_y, -pcbThickness),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 1, 0), 180),
+ )
+ # obj.Placement = impPart.Placement
+ if impPart.TypeId in {"App::Link", "App::LinkPython"}:
+ shape = Part.getShape(o)
else:
- shape=impPart.Shape.copy()
- shape.Placement=impPart.Placement;
- #if not full_placement:
- #shape.rotate((pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,-pcbThickness+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1])+180,-float(wrl_rot[0])))
- #else:
- shape.rotate((pos_x,pos_y,-pcbThickness),(0,0,1),-rot+180)
- impPart.Placement=shape.Placement
+ shape = impPart.Shape.copy()
+ shape.Placement = impPart.Placement
+ # if not full_placement:
+ # shape.rotate((pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,-pcbThickness+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1])+180,-float(wrl_rot[0])))
+ # else:
+ shape.rotate((pos_x, pos_y, -pcbThickness), (0, 0, 1), -rot + 180)
+ impPart.Placement = shape.Placement
FreeCADGui.Selection.addSelection(impPart)
FreeCAD.ActiveDocument.getObject(impPart.Name)
if isVirtual == 0:
- if use_AppPart and not use_LinkGroups: #layer Top
+ if use_AppPart and not use_LinkGroups: # layer Top
FreeCAD.ActiveDocument.getObject(bot_name).addObject(impPart)
- modelBot_nbr+=1
+ modelBot_nbr += 1
elif use_LinkGroups:
- #FreeCAD.ActiveDocument.getObject(impPart.Name).adjustRelativeLinks(FreeCAD.ActiveDocument.getObject('Bot'))
- FreeCAD.ActiveDocument.getObject(bot_name).ViewObject.dropObject(FreeCAD.ActiveDocument.getObject(impPart.Name),FreeCAD.ActiveDocument.getObject(impPart.Name),'',[])
- modelBot_nbr+=1
+ # FreeCAD.ActiveDocument.getObject(impPart.Name).adjustRelativeLinks(FreeCAD.ActiveDocument.getObject('Bot'))
+ FreeCAD.ActiveDocument.getObject(bot_name).ViewObject.dropObject(
+ FreeCAD.ActiveDocument.getObject(impPart.Name),
+ FreeCAD.ActiveDocument.getObject(impPart.Name),
+ "",
+ [],
+ )
+ modelBot_nbr += 1
else:
FreeCAD.ActiveDocument.getObject(stepM_name).addObject(impPart)
- else: #virtual
- if use_AppPart and not use_LinkGroups: #layer Top
+ else: # virtual
+ if use_AppPart and not use_LinkGroups: # layer Top
FreeCAD.ActiveDocument.getObject(botV_name).addObject(impPart)
- virtualBot_nbr+=1
+ virtualBot_nbr += 1
elif use_LinkGroups:
- #FreeCAD.ActiveDocument.getObject(impPart.Name).adjustRelativeLinks(FreeCAD.ActiveDocument.getObject('BotV'))
- FreeCAD.ActiveDocument.getObject(botV_name).ViewObject.dropObject(FreeCAD.ActiveDocument.getObject(impPart.Name),FreeCAD.ActiveDocument.getObject(impPart.Name),'',[])
- virtualBot_nbr+=1
+ # FreeCAD.ActiveDocument.getObject(impPart.Name).adjustRelativeLinks(FreeCAD.ActiveDocument.getObject('BotV'))
+ FreeCAD.ActiveDocument.getObject(botV_name).ViewObject.dropObject(
+ FreeCAD.ActiveDocument.getObject(impPart.Name),
+ FreeCAD.ActiveDocument.getObject(impPart.Name),
+ "",
+ [],
+ )
+ virtualBot_nbr += 1
else:
FreeCAD.ActiveDocument.getObject(stepV_name).addObject(impPart)
- virtual_nbr+=1
+ virtual_nbr += 1
###
- elif module_path=='internal shape':
- impPart=FreeCAD.ActiveDocument.ActiveObject
- scale_vrml=modules[i][8]
- #sayw(scale_vrml)
- #scale_val=scale_vrml.split(" ")
- scale_val=scale_vrml
- #sayw(scale_val)
- pos_x=modules[i][1]-off_x
- pos_y=modules[i][2]-off_y
- rot=modules[i][3]
- wrl_rot=modules[i][7]
- step_layer=modules[i][4]
- #wrl_off_x=modules[i][6]
- #rotz_vrml_norm=modules[i][7][0].replace("(xyz ","")
- #rotz_vrml_norm=modules[i][7].replace("(xyz ","")
- #say("rotz_vrml_norm ");sayw(rotz_vrml_norm)
- #wrl_rot=rotz_vrml_norm.split(" ")
- pos_vrml=modules[i][6]
- wrl_pos=pos_vrml
- #wrl_pos=pos_vrml[0].split(" ")
- #wrl_pos=pos_vrml.split(" ")
- #say(rotz_vrml_norm)
- #sayw("wrl rot ");sayw(wrl_rot)
- #say("wrl pos ");sayw(wrl_pos)
- shape_vol=abs(float(scale_val[0])*float(scale_val[1])*float(scale_val[2]))
- skip_status="not"
- if shape_vol>volume_minimum: #mauitemp min vol
- if abs(float(scale_val[2]))>height_minimum: #mauitemp min height
- if (height_minimum!=0):
- say("height > Min height "+ str(scale_val[2]) + " "+impPart.Label)
- if (volume_minimum!=0):
- say("Volume > Min Volume "+ str(shape_vol) + " "+impPart.Label)
+ elif module_path == "internal shape":
+ impPart = FreeCAD.ActiveDocument.ActiveObject
+ scale_vrml = modules[i][8]
+ # sayw(scale_vrml)
+ # scale_val=scale_vrml.split(" ")
+ scale_val = scale_vrml
+ # sayw(scale_val)
+ pos_x = modules[i][1] - off_x
+ pos_y = modules[i][2] - off_y
+ rot = modules[i][3]
+ wrl_rot = modules[i][7]
+ step_layer = modules[i][4]
+ # wrl_off_x=modules[i][6]
+ # rotz_vrml_norm=modules[i][7][0].replace("(xyz ","")
+ # rotz_vrml_norm=modules[i][7].replace("(xyz ","")
+ # say("rotz_vrml_norm ");sayw(rotz_vrml_norm)
+ # wrl_rot=rotz_vrml_norm.split(" ")
+ pos_vrml = modules[i][6]
+ wrl_pos = pos_vrml
+ # wrl_pos=pos_vrml[0].split(" ")
+ # wrl_pos=pos_vrml.split(" ")
+ # say(rotz_vrml_norm)
+ # sayw("wrl rot ");sayw(wrl_rot)
+ # say("wrl pos ");sayw(wrl_pos)
+ shape_vol = abs(float(scale_val[0]) * float(scale_val[1]) * float(scale_val[2]))
+ skip_status = "not"
+ if shape_vol > volume_minimum: # mauitemp min vol
+ if abs(float(scale_val[2])) > height_minimum: # mauitemp min height
+ if height_minimum != 0:
+ say("height > Min height " + str(scale_val[2]) + " " + impPart.Label)
+ if volume_minimum != 0:
+ say("Volume > Min Volume " + str(shape_vol) + " " + impPart.Label)
else:
- skip_status="skip"
- say("height <= Min height "+ str(scale_val[2]) + " "+impPart.Label)
+ skip_status = "skip"
+ say("height <= Min height " + str(scale_val[2]) + " " + impPart.Label)
else:
- skip_status="skip"
- say("Volume <= Min Volume "+ str(shape_vol) + " "+impPart.Label)
- if skip_status=="not":
- if step_layer == 'Top':
+ skip_status = "skip"
+ say("Volume <= Min Volume " + str(shape_vol) + " " + impPart.Label)
+ if skip_status == "not":
+ if step_layer == "Top":
if full_placement:
## new placement wip
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0]),pos_y+float(wrl_pos[1]),0+float(wrl_pos[2])),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),rot))
- # (yaw z, pitch y, roll x)
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,0+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1]),-float(wrl_rot[0])))
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,0+float(wrl_pos[2])*25.4),FreeCAD.Rotation(rot,-float(wrl_rot[1]),-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,0+float(wrl_pos[2])*25.4),FreeCAD.Rotation(rot,-float(wrl_rot[1]),-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
- impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,0+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1]),-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
- shape=impPart.Shape.copy()
- shape.Placement=impPart.Placement;
- shape.rotate((pos_x,pos_y,0),(0,0,1),rot+float(wrl_rot[2]))
- impPart.Placement=shape.Placement;
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0]),pos_y+float(wrl_pos[1]),0+float(wrl_pos[2])),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),rot))
+ # (yaw z, pitch y, roll x)
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,0+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1]),-float(wrl_rot[0])))
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,0+float(wrl_pos[2])*25.4),FreeCAD.Rotation(rot,-float(wrl_rot[1]),-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,0+float(wrl_pos[2])*25.4),FreeCAD.Rotation(rot,-float(wrl_rot[1]),-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
+ impPart.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(
+ pos_x + float(wrl_pos[0]) * 25.4,
+ pos_y + float(wrl_pos[1]) * 25.4,
+ 0 + float(wrl_pos[2]) * 25.4,
+ ),
+ FreeCAD.Rotation(-float(wrl_rot[2]), -float(wrl_rot[1]), -float(wrl_rot[0])),
+ ) # rot is already rot fp -rot wrl
+ shape = impPart.Shape.copy()
+ shape.Placement = impPart.Placement
+ shape.rotate((pos_x, pos_y, 0), (0, 0, 1), rot + float(wrl_rot[2]))
+ impPart.Placement = shape.Placement
if force_transparency:
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=100
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = 100
##TBChecked shapes
- #say("rot z top ");sayw(wrl_rot);sayw(rot)
+ # say("rot z top ");sayw(wrl_rot);sayw(rot)
else:
- impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x,pos_y,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),rot))
+ impPart.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(pos_x, pos_y, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), rot),
+ )
FreeCADGui.Selection.addSelection(impPart)
- if use_AppPart: #Top
+ if use_AppPart: # Top
FreeCAD.ActiveDocument.getObject(top_name).addObject(impPart)
- modelTop_nbr+=1
+ modelTop_nbr += 1
else:
FreeCAD.ActiveDocument.getObject(stepM_name).addObject(impPart)
else:
- #Bottom
- #Bottom
- #impPart=reset_prop_shapes2(impPart,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
+ # Bottom
+ # Bottom
+ # impPart=reset_prop_shapes2(impPart,FreeCAD.ActiveDocument, FreeCAD,FreeCADGui)
if full_placement:
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x,pos_y,-pcbThickness),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x,pos_y,-pcbThickness),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
## new placement wip
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[1])*25.4,pos_y+float(wrl_pos[0])*25.4,-pcbThickness-float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2])-rot+180,-float(wrl_rot[1])+180,-float(wrl_rot[0])))
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[1])*25.4,pos_y+float(wrl_pos[0])*25.4,-pcbThickness-float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2])-rot+180,-float(wrl_rot[1])+180,-float(wrl_rot[0])))
# impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[1])*25.4,pos_y+float(wrl_pos[0])*25.4,-pcbThickness),FreeCAD.Rotation(-float(wrl_rot[2])+180,-float(wrl_rot[1])+180,-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
# #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[1])*25.4,pos_y+float(wrl_pos[0])*25.4,-pcbThickness-float(wrl_pos[2])*25.4),FreeCAD.Rotation(float(wrl_rot[2]),-float(wrl_rot[1]),-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
# shape=impPart.Shape.copy()
# shape.Placement=impPart.Placement;
# shape.rotate((pos_x+float(wrl_pos[1])*25.4,pos_y+float(wrl_pos[0])*25.4,-pcbThickness-float(wrl_pos[2])*25.4),(0,0,1),-180+rot-float(wrl_rot[2]))
# impPart.Placement=shape.Placement;
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[1])*25.4,pos_y+float(wrl_pos[0])*25.4,-pcbThickness-float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2])-rot+180,-float(wrl_rot[1])+180,-float(wrl_rot[0])))
- impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,+pcbThickness+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1]),-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
- shape=impPart.Shape.copy()
- shape.Placement=impPart.Placement;
- shape.rotate((pos_x,pos_y,0),(0,0,1),180+rot+float(wrl_rot[2]))
- impPart.Placement=shape.Placement;
- shape=impPart.Shape.copy()
- shape.Placement=impPart.Placement;
- shape.rotate((pos_x,pos_y,0),(0,1,0),180)
- impPart.Placement=shape.Placement;
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[1])*25.4,pos_y+float(wrl_pos[0])*25.4,-pcbThickness-float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2])-rot+180,-float(wrl_rot[1])+180,-float(wrl_rot[0])))
+ impPart.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(
+ pos_x + float(wrl_pos[0]) * 25.4,
+ pos_y + float(wrl_pos[1]) * 25.4,
+ +pcbThickness + float(wrl_pos[2]) * 25.4,
+ ),
+ FreeCAD.Rotation(-float(wrl_rot[2]), -float(wrl_rot[1]), -float(wrl_rot[0])),
+ ) # rot is already rot fp -rot wrl
+ shape = impPart.Shape.copy()
+ shape.Placement = impPart.Placement
+ shape.rotate((pos_x, pos_y, 0), (0, 0, 1), 180 + rot + float(wrl_rot[2]))
+ impPart.Placement = shape.Placement
+ shape = impPart.Shape.copy()
+ shape.Placement = impPart.Placement
+ shape.rotate((pos_x, pos_y, 0), (0, 1, 0), 180)
+ impPart.Placement = shape.Placement
if force_transparency:
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=60
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
##TBChecked shapes
- #say("rot z bot ");sayw(wrl_rot);sayw(rot)
- #impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,-pcbThickness+float(wrl_pos[2])*25.4),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
+ # say("rot z bot ");sayw(wrl_rot);sayw(rot)
+ # impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,-pcbThickness+float(wrl_pos[2])*25.4),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
else:
- impPart.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x,pos_y,-pcbThickness),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
- #obj.Placement = impPart.Placement
- shape=impPart.Shape.copy()
- shape.Placement=impPart.Placement;
- #if not full_placement:
- #shape.rotate((pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,-pcbThickness+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1])+180,-float(wrl_rot[0])))
- #else:
- shape.rotate((pos_x,pos_y,-pcbThickness),(0,0,1),-rot+180)
- impPart.Placement=shape.Placement
+ impPart.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(pos_x, pos_y, -pcbThickness),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 1, 0), 180),
+ )
+ # obj.Placement = impPart.Placement
+ shape = impPart.Shape.copy()
+ shape.Placement = impPart.Placement
+ # if not full_placement:
+ # shape.rotate((pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,-pcbThickness+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1])+180,-float(wrl_rot[0])))
+ # else:
+ shape.rotate((pos_x, pos_y, -pcbThickness), (0, 0, 1), -rot + 180)
+ impPart.Placement = shape.Placement
FreeCADGui.Selection.addSelection(impPart)
FreeCAD.ActiveDocument.getObject(impPart.Name)
- if use_AppPart: #Bot
+ if use_AppPart: # Bot
FreeCAD.ActiveDocument.getObject("Bot").addObject(impPart)
- modelBot_nbr+=1
+ modelBot_nbr += 1
else:
FreeCAD.ActiveDocument.getObject(stepM_name).addObject(impPart)
- else:
+ else:
FreeCAD.ActiveDocument.removeObject(impPart.Name)
else:
- #say("error missing "+ make_string(models3D_prefix)+make_string(step_module))
- say("error missing "+ make_string(module_container))
- #test = missing_models.find(make_string(step_module))
+ # say("error missing "+ make_string(models3D_prefix)+make_string(step_module))
+ say("error missing " + make_string(module_container))
+ # test = missing_models.find(make_string(step_module))
test = missing_models.find(make_string(module_container))
if test == -1:
- #missing_models += make_string(models3D_prefix)+make_string(step_module)+'\r\n' #matched
- # missing_models += make_string(step_module)+'\r\n' #matched
- missing_models += make_string(module_container)+' (.stp or .step)\r\n' #matched
+ # missing_models += make_string(models3D_prefix)+make_string(step_module)+'\r\n' #matched
+ # missing_models += make_string(step_module)+'\r\n' #matched
+ missing_models += make_string(module_container) + " (.stp or .step)\r\n" # matched
###
- gui_refresh=20
- if int(PySide.QtCore.qVersion().split('.')[0]) > 4 or use_Links: # Qt5 or Links refresh
- if mod_cnt%gui_refresh == 0: # (one on 'gui_refresh' times)
- #FreeCADGui.updateGui()
+ gui_refresh = 20
+ if int(PySide.QtCore.qVersion().split(".")[0]) > 4 or use_Links: # Qt5 or Links refresh
+ if mod_cnt % gui_refresh == 0: # (one on 'gui_refresh' times)
+ # FreeCADGui.updateGui()
QtGui.QApplication.processEvents()
###
- sayw('added '+str(mod_cnt)+' model(s)')
+ sayw("added " + str(mod_cnt) + " model(s)")
###
###
- #say(loaded_models);
- #sleep
- if virtual_nbr==0:
- #FreeCAD.ActiveDocument.getObject("Step_Virtual_Models").removeObjectsFromDocument()
+ # say(loaded_models);
+ # sleep
+ if virtual_nbr == 0:
+ # FreeCAD.ActiveDocument.getObject("Step_Virtual_Models").removeObjectsFromDocument()
FreeCAD.ActiveDocument.removeObject(stepV_name)
if use_AppPart:
FreeCAD.ActiveDocument.removeObject(botV_name)
FreeCAD.ActiveDocument.removeObject(topV_name)
- else:
- if use_AppPart:
- if virtualTop_nbr==0:
- #FreeCAD.ActiveDocument.getObject("TopV").removeObjectsFromDocument()
- FreeCAD.ActiveDocument.removeObject(topV_name)
- #FreeCAD.ActiveDocument.recompute()
- if virtualBot_nbr==0:
- #FreeCAD.ActiveDocument.getObject("BotV").removeObjectsFromDocument()
- FreeCAD.ActiveDocument.removeObject(botV_name)
- #FreeCAD.ActiveDocument.recompute()
+ elif use_AppPart:
+ if virtualTop_nbr == 0:
+ # FreeCAD.ActiveDocument.getObject("TopV").removeObjectsFromDocument()
+ FreeCAD.ActiveDocument.removeObject(topV_name)
+ # FreeCAD.ActiveDocument.recompute()
+ if virtualBot_nbr == 0:
+ # FreeCAD.ActiveDocument.getObject("BotV").removeObjectsFromDocument()
+ FreeCAD.ActiveDocument.removeObject(botV_name)
+ # FreeCAD.ActiveDocument.recompute()
if use_AppPart:
- if modelTop_nbr==0:
- #FreeCAD.ActiveDocument.getObject("Top").removeObjectsFromDocument()
- FreeCAD.ActiveDocument.removeObject(top_name)
- if modelBot_nbr==0:
- #FreeCAD.ActiveDocument.getObject("Bot").removeObjectsFromDocument()
- FreeCAD.ActiveDocument.removeObject(bot_name)
-
+ if modelTop_nbr == 0:
+ # FreeCAD.ActiveDocument.getObject("Top").removeObjectsFromDocument()
+ FreeCAD.ActiveDocument.removeObject(top_name)
+ if modelBot_nbr == 0:
+ # FreeCAD.ActiveDocument.getObject("Bot").removeObjectsFromDocument()
+ FreeCAD.ActiveDocument.removeObject(bot_name)
+
FreeCAD.ActiveDocument.recompute()
say_time()
FreeCADGui.Selection.clearSelection()
- if 0: #try
- print('TreeView Test collapsing')
+ if 0: # try
+ print("TreeView Test collapsing")
FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Board)
- import kicadStepUpCMD
- FreeCADGui.runCommand('ksuToolsToggleTreeView',0)
- s=FreeCADGui.Selection.getSelection()[0]
+ FreeCADGui.runCommand("ksuToolsToggleTreeView", 0)
+ s = FreeCADGui.Selection.getSelection()[0]
print(s.Label)
- FreeCADGui.runCommand('ksuToolsToggleTreeView',0)
- #kicadStepUpCMD.ksuToolsToggleTreeView.Activated(s)
- #FreeCADGui.Selection.clearSelection()
- #FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Board)
- #s=FreeCADGui.Selection.getSelection()[0]
- #print(s.Label)
- #kicadStepUpCMD.ksuToolsToggleTreeView.Activated(s)
+ FreeCADGui.runCommand("ksuToolsToggleTreeView", 0)
+ # kicadStepUpCMD.ksuToolsToggleTreeView.Activated(s)
+ # FreeCADGui.Selection.clearSelection()
+ # FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Board)
+ # s=FreeCADGui.Selection.getSelection()[0]
+ # print(s.Label)
+ # kicadStepUpCMD.ksuToolsToggleTreeView.Activated(s)
FreeCADGui.Selection.clearSelection()
- elif 0: #except:
- import expTree;
- print('TreeView Test collapsing 2')
- #import importlib; importlib.reload(expTree);
+ elif 0: # except:
+ import expTree
+
+ print("TreeView Test collapsing 2")
+ # import importlib; importlib.reload(expTree);
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Board)
expTree.collS_Tree()
FreeCADGui.Selection.clearSelection()
- print('TreeView Test collapsing 2 step 2')
+ print("TreeView Test collapsing 2 step 2")
else:
pass
- #print (my_hide_list)
+ # print (my_hide_list)
if my_hide_list != "":
- n_rpt_max=10
- sayw(str(len(my_hide_list.split('\r\n'))-1)+" model[s] hidden")
- sayw(str(my_hide_list.split('\r\n')[:-1]))
+ n_rpt_max = 10
+ sayw(str(len(my_hide_list.split("\r\n")) - 1) + " model[s] hidden")
+ sayw(str(my_hide_list.split("\r\n")[:-1]))
my_hide_res = []
- my_hide_res = my_hide_list.split('\r\n')
- wmsg="""... model[s] hidden
"""
- for i in range(min(len (my_hide_res),n_rpt_max)):
- wmsg=wmsg+my_hide_res[i]+'
'
+ my_hide_res = my_hide_list.split("\r\n")
+ wmsg = """... model[s] hidden
"""
+ for i in range(min(len(my_hide_res), n_rpt_max)):
+ wmsg = wmsg + my_hide_res[i] + "
"
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Warning ...",wmsg+'. . . '+str(len(my_hide_res)-1)+' model[s] hidden' )
-
- if missing_models != '':
+ QtGui.QMessageBox.information(
+ None,
+ "Warning ...",
+ wmsg + ". . . " + str(len(my_hide_res) - 1) + " model[s] hidden",
+ )
+
+ if missing_models != "":
last_pcb_path_local = re.sub("\\\\", "/", last_pcb_path)
last_pcb_path_local_U = make_unicode(last_pcb_path_local)
- say("missing models");say (missing_models)
+ say("missing models")
+ say(missing_models)
say("searching path")
for mpath in path_list:
say(mpath)
- #say(models3D_prefix_U);say (models3D_prefix2_U)
+ # say(models3D_prefix_U);say (models3D_prefix2_U)
say(last_pcb_path_local_U)
- missings=[]
- missings=missing_models.split('\r\n')
- n_rpt_max=10
- #if len (missings) > n_rpt_max: #warning_nbr =-1 for skipping the test
- wmsg="""... missing module(s)
"""
- wmsg+="""... searching path:
"""
+ missings = []
+ missings = missing_models.split("\r\n")
+ n_rpt_max = 10
+ # if len (missings) > n_rpt_max: #warning_nbr =-1 for skipping the test
+ wmsg = """... missing module(s)
"""
+ wmsg += """... searching path:
"""
for mpath in path_list:
- wmsg+=mpath+"""
"""
- #wmsg+=models3D_prefix_U+"""
"""
- #wmsg+=models3D_prefix2_U+"""
"""
- wmsg+=last_pcb_path_local_U+"""
"""
- wmsg+="""... missing module(s) '.step' or '.stp' or .iges' or '.igs'
"""
- for i in range(min(len (missings),n_rpt_max)):
- wmsg=wmsg+missings[i]+'
'
+ wmsg += mpath + """
"""
+ # wmsg+=models3D_prefix_U+"""
"""
+ # wmsg+=models3D_prefix2_U+"""
"""
+ wmsg += last_pcb_path_local_U + """
"""
+ wmsg += """... missing module(s) '.step' or '.stp' or .iges' or '.igs'
"""
+ for i in range(min(len(missings), n_rpt_max)):
+ wmsg = wmsg + missings[i] + "
"
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Error ...",wmsg+'
. . . missing '+str(len(missings)-1)+' model(s)' )
- if len (missings) > warning_nbr and warning_nbr != -1: #warning_nbr =-1 for skipping the test
+ QtGui.QMessageBox.information(
+ None,
+ "Error ...",
+ wmsg + "
. . . missing " + str(len(missings) - 1) + " model(s)",
+ )
+ if len(missings) > warning_nbr and warning_nbr != -1: # warning_nbr =-1 for skipping the test
QtGui.QApplication.restoreOverrideCursor()
- wmsg=""""""
- wmsg+="too many missing modules ["
- wmsg+=str(len (missings))+"]
Have you configured your KISYS3DMOD path
or 3d model prefix path?"
- wmsg+="
StepUp configuration options are located in the preferences system of FreeCAD."
- wmsg+="
Are you on FC Snap or Flatpack?
You may need to \'bind mount\' your 3d models folder"
- reply = QtGui.QMessageBox.information(None,"Error ...",wmsg)
- #if blacklisted_model_elements != '':
+ wmsg = """"""
+ wmsg += "too many missing modules ["
+ wmsg += (
+ str(len(missings))
+ + "]
Have you configured your KISYS3DMOD path
or 3d model prefix path?"
+ )
+ wmsg += "
StepUp configuration options are located in the preferences system of FreeCAD."
+ wmsg += "
Are you on FC Snap or Flatpack?
You may need to 'bind mount' your 3d models folder"
+ QtGui.QMessageBox.information(None, "Error ...", wmsg)
+ # if blacklisted_model_elements != '':
# FreeCAD.Console.PrintMessage("black-listed module "+ '\n'.join(map(str, blacklisted_models)))
# reply = QtGui.QMessageBox.information(None,"Info ...","... black-listed module(s)\n"+ '\n'.join(map(str, blacklisted_models)))
# #FreeCAD.Console.PrintMessage("black-listed module "+ '\n'.join(map(str, blacklisted_models)))
return blacklisted_model_elements
+
+
###
-def getPads(board_elab,pcbThickness):
+
+def getPads(board_elab, pcbThickness):
# pad
- TopPadList=[]
- BotPadList=[]
- HoleList=[]
- THPList=[]
- for module in re.findall(r'\[start\]\(module(.+?)\)\[stop\]', board_elab, re.MULTILINE|re.DOTALL):
- [X1, Y1, ROT] = re.search(r'\(at\s+([0-9\.-]*?)\s+([0-9\.-]*?)(\s+[0-9\.-]*?|)\)', module).groups()
- #
+ HoleList = []
+ for module in re.findall(r"\[start\]\(module(.+?)\)\[stop\]", board_elab, re.MULTILINE | re.DOTALL):
+ [X1, Y1, ROT] = re.search(r"\(at\s+([0-9\.-]*?)\s+([0-9\.-]*?)(\s+[0-9\.-]*?|)\)", module).groups()
X1 = float(X1)
Y1 = float(Y1) * (-1)
- if ROT == '':
- ROT = 0.0
- else:
- ROT = float(ROT)
- #say('module pos & rot '+str(X1)+' '+str(Y1)+' '+str(ROT))
+ ROT = 0.0 if ROT == "" else float(ROT)
+ # say('module pos & rot '+str(X1)+' '+str(Y1)+' '+str(ROT))
#
for pad in getPadsList(module):
- #say (pad)
+ # say (pad)
# pads.append({'x': x, 'y': y, 'rot': rot, 'padType': pType, 'padShape': pShape, 'rx': drill_x, 'ry': drill_y, 'dx': dx, 'dy': dy, 'holeType': hType, 'xOF': xOF, 'yOF': yOF, 'layers': layers})
- pType = pad['padType']
- pShape = pad['padShape']
- xs = pad['x'] + X1
- ys = pad['y'] + Y1
- dx = pad['dx']
- dy = pad['dy']
- hType = pad['holeType']
- drill_x = pad['rx']
- drill_y = pad['ry']
- xOF = pad['xOF']
- yOF = pad['yOF']
- rot = pad['rot']
+ pad["padType"]
+ pShape = pad["padShape"]
+ xs = pad["x"] + X1
+ ys = pad["y"] + Y1
+ dx = pad["dx"]
+ dy = pad["dy"]
+ pad["holeType"]
+ drill_x = pad["rx"]
+ drill_y = pad["ry"]
+ xOF = pad["xOF"]
+ yOF = pad["yOF"]
+ rot = pad["rot"]
if ROT != 0:
rot -= ROT
- rx=drill_x
- ry=drill_y
- rx=float(rx)
- ry=float(ry)
- numberOfLayers = pad['layers'].split(' ')
- #if pType=="thru_hole":
- #pad shape - circle/rec/oval/trapezoid
- perc=0
- if pShape=="circle" or pShape=="oval":
- pShape="oval"
- perc=100
+ rx = drill_x
+ ry = drill_y
+ rx = float(rx)
+ ry = float(ry)
+ numberOfLayers = pad["layers"].split(" ")
+ # if pType=="thru_hole":
+ # pad shape - circle/rec/oval/trapezoid
+ if pShape in {"circle", "oval"}:
+ pShape = "oval"
# pad type - SMD/thru_hole/connect
- if dx>rx and dy>ry:
- #say(pType)
- #say(str(dx)+"+"+str(rx)+" dx,rx")
- #say(str(dy)+"+"+str(ry)+" dy,ry")
- #say(str(xOF)+"+"+str(yOF)+" xOF,yOF")
- x1=xs+xOF
- y1=ys-yOF #yoffset opposite
- #say(str(x1)+"+"+str(y1)+" x1,y1")
- top=False
- bot=False
- if 'F.Cu' in numberOfLayers:
- top=True
- if '*.Cu' in numberOfLayers:
- top=True
- bot=True
- if 'B.Cu' in numberOfLayers:
- bot=True
- if rx!=0:
- #say(str(min_drill_size));say(' ');say(rx);say(' ');say(str(ry));
+ if dx > rx and dy > ry:
+ # say(pType)
+ # say(str(dx)+"+"+str(rx)+" dx,rx")
+ # say(str(dy)+"+"+str(ry)+" dy,ry")
+ # say(str(xOF)+"+"+str(yOF)+" xOF,yOF")
+ xs + xOF
+ ys - yOF # yoffset opposite
+ # say(str(x1)+"+"+str(y1)+" x1,y1")
+ if "F.Cu" in numberOfLayers:
+ pass
+ if "*.Cu" in numberOfLayers:
+ pass
+ if "B.Cu" in numberOfLayers:
+ pass
+ if rx != 0:
+ # say(str(min_drill_size));say(' ');say(rx);say(' ');say(str(ry));
if (rx >= min_drill_size) or (ry >= min_drill_size):
- obj=createHole3(xs,ys,rx,ry,"oval",pcbThickness) #need to be separated instructions
- #say(HoleList)
- if rot!=0:
+ obj = createHole3(xs, ys, rx, ry, "oval", pcbThickness) # need to be separated instructions
+ # say(HoleList)
+ if rot != 0:
rotateObj(obj, [xs, ys, rot])
rotateObj(obj, [X1, Y1, ROT])
- HoleList.append(obj)
+ HoleList.append(obj)
### cmt- #todo: pad type trapez
return HoleList
+
+
###
def getPads_flat(board_elab):
# pad
- TopPadList=[]
- BotPadList=[]
- HoleList=[]
- THPList=[]
- for module in re.findall(r'\[start\]\(module(.+?)\)\[stop\]', board_elab, re.MULTILINE|re.DOTALL):
- [X1, Y1, ROT] = re.search(r'\(at\s+([0-9\.-]*?)\s+([0-9\.-]*?)(\s+[0-9\.-]*?|)\)', module).groups()
- #
+ HoleList = []
+ for module in re.findall(r"\[start\]\(module(.+?)\)\[stop\]", board_elab, re.MULTILINE | re.DOTALL):
+ [X1, Y1, ROT] = re.search(r"\(at\s+([0-9\.-]*?)\s+([0-9\.-]*?)(\s+[0-9\.-]*?|)\)", module).groups()
X1 = float(X1)
Y1 = float(Y1) * (-1)
- if ROT == '':
- ROT = 0.0
- else:
- ROT = float(ROT)
- #say('module pos & rot '+str(X1)+' '+str(Y1)+' '+str(ROT))
+ ROT = 0.0 if ROT == "" else float(ROT)
+ # say('module pos & rot '+str(X1)+' '+str(Y1)+' '+str(ROT))
#
for pad in getPadsList(module):
- #say (pad)
+ # say (pad)
#
# pads.append({'x': x, 'y': y, 'rot': rot, 'padType': pType, 'padShape': pShape, 'rx': drill_x, 'ry': drill_y, 'dx': dx, 'dy': dy, 'holeType': hType, 'xOF': xOF, 'yOF': yOF, 'layers': layers})
- pType = pad['padType']
- pShape = pad['padShape']
- xs = pad['x'] + X1
- ys = pad['y'] + Y1
- dx = pad['dx']
- dy = pad['dy']
- hType = pad['holeType']
- drill_x = pad['rx']
- drill_y = pad['ry']
- xOF = pad['xOF']
- yOF = pad['yOF']
- rot = pad['rot']
+ pad["padType"]
+ pShape = pad["padShape"]
+ xs = pad["x"] + X1
+ ys = pad["y"] + Y1
+ dx = pad["dx"]
+ dy = pad["dy"]
+ pad["holeType"]
+ drill_x = pad["rx"]
+ drill_y = pad["ry"]
+ xOF = pad["xOF"]
+ yOF = pad["yOF"]
+ rot = pad["rot"]
if ROT != 0:
rot -= ROT
- rx=drill_x
- ry=drill_y
- rx=float(rx)
- ry=float(ry)
- numberOfLayers = pad['layers'].split(' ')
- #say(numberOfLayers )
- #if pType=="thru_hole":
- #pad shape - circle/rec/oval/trapezoid
- perc=0
- if pShape=="circle" or pShape=="oval":
- pShape="oval"
- perc=100
+ rx = drill_x
+ ry = drill_y
+ rx = float(rx)
+ ry = float(ry)
+ numberOfLayers = pad["layers"].split(" ")
+ # say(numberOfLayers )
+ # if pType=="thru_hole":
+ # pad shape - circle/rec/oval/trapezoid
+ if pShape in {"circle", "oval"}:
+ pShape = "oval"
# pad type - SMD/thru_hole/connect
- if dx>rx and dy>ry:
- #say(pType+"")
- #say(str(dx)+"+"+str(rx)+" dx,rx")
- #say(str(dy)+"+"+str(ry)+" dy,ry")
- #say(str(xOF)+"+"+str(yOF)+" xOF,yOF")
- x1=xs+xOF
- y1=ys-yOF #yoffset opposite
- #say(str(x1)+"+"+str(y1)+" x1,y1")
- top=False
- bot=False
- if 'F.Cu' in numberOfLayers:
- top=True
- if '*.Cu' in numberOfLayers:
- top=True
- bot=True
- if 'B.Cu' in numberOfLayers:
- bot=True
- if rx!=0:
- #say(str(min_drill_size));say(' ');say(rx);say(' ');say(str(ry));
- #if (rx > min_drill_size):
+ if dx > rx and dy > ry:
+ # say(pType+"")
+ # say(str(dx)+"+"+str(rx)+" dx,rx")
+ # say(str(dy)+"+"+str(ry)+" dy,ry")
+ # say(str(xOF)+"+"+str(yOF)+" xOF,yOF")
+ xs + xOF
+ ys - yOF # yoffset opposite
+ # say(str(x1)+"+"+str(y1)+" x1,y1")
+ if "F.Cu" in numberOfLayers:
+ pass
+ if "*.Cu" in numberOfLayers:
+ pass
+ if "B.Cu" in numberOfLayers:
+ pass
+ if rx != 0:
+ # say(str(min_drill_size));say(' ');say(rx);say(' ');say(str(ry));
+ # if (rx > min_drill_size):
if (rx >= min_drill_size) or (ry >= min_drill_size):
- #obj=createHole3(xs,ys,rx,ry,"oval",pcbThickness) #need to be separated instructions
- obj=createHole4(xs,ys,rx,ry,"oval") #need to be separated instructions
- #say(HoleList)
- if rot!=0:
+ # obj=createHole3(xs,ys,rx,ry,"oval",pcbThickness) #need to be separated instructions
+ obj = createHole4(xs, ys, rx, ry, "oval") # need to be separated instructions
+ # say(HoleList)
+ if rot != 0:
rotateObj(obj, [xs, ys, rot])
rotateObj(obj, [X1, Y1, ROT])
HoleList.append(obj)
### cmt- #todo: pad type trapez
return HoleList
+
+
###
+
def Elaborate_Kicad_Board(filename):
global xMax, xmin, yMax, ymin
global ignore_utf8, ignore_utf8_incfg
- Levels={}
- content=[]
- #txtFile = __builtin__.open(filename,"r")
+ Levels = {}
+ content = []
+ # txtFile = __builtin__.open(filename,"r")
##txtFile = __builtin__.open(filename,"rb")
- txtFile = codecs.open(filename, mode='rb', encoding='utf-8', errors='replace', buffering=1) #test maui utf-8
- content = txtFile.readlines()
+ with codecs.open(
+ filename, mode="rb", encoding="utf-8", errors="replace", buffering=1
+ ) as txtFile: # test maui utf-8
+ content = txtFile.readlines()
content.append(" ")
- txtFile.close()
- data=''.join(content)
+ data = "".join(content)
if ignore_utf8:
- content=re.sub(r'[^\x00-\x7F]+',' ', data) #workaround to remove utf8 extra chars
- sayw('removing utf-8 chars')
+ content = re.sub(r"[^\x00-\x7F]+", " ", data) # workaround to remove utf8 extra chars
+ sayw("removing utf-8 chars")
else:
- content=data
+ content = data
## content=data
- #say(len(content))
- Kicad_Board_elaborated = content #''.join(content)
+ # say(len(content))
+ Kicad_Board_elaborated = content #''.join(content)
if save_temp_data:
home = expanduser("~")
- t1_name=home+os.sep+'test.txt'
- #f = __builtin__.open(t1_name,'w')
+ t1_name = home + os.sep + "test.txt"
+ # f = __builtin__.open(t1_name,'w')
# f = builtin.open(t1_name,'wb') #py2
- f = builtin.open(t1_name,'w') #py3
- f.write(Kicad_Board_elaborated) # python will convert \n to os.linesep
- f.close() # you can omit in most cases as the destructor will call it
- #say(len(Kicad_Board_elaborated))
- #stop
- version=getPCBVersion(Kicad_Board_elaborated)
- pcbThickness=getPCBThickness(Kicad_Board_elaborated)
- say('kicad_pcb version ' +str(version))
+ with builtin.open(t1_name, "w") as f: # py3
+ f.write(Kicad_Board_elaborated) # python will convert \n to os.linesep
+ # say(len(Kicad_Board_elaborated))
+ # stop
+ version = getPCBVersion(Kicad_Board_elaborated)
+ pcbThickness = getPCBThickness(Kicad_Board_elaborated)
+ say("kicad_pcb version " + str(version))
if version < 3:
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Error ...","... KICAD pcb version "+ str(version)+" not supported \r\n"+"\r\nplease open and save your board with the latest kicad version")
+ QtGui.QMessageBox.information(
+ None,
+ "Error ...",
+ "... KICAD pcb version "
+ + str(version)
+ + " not supported \r\n"
+ + "\r\nplease open and save your board with the latest kicad version",
+ )
sys.exit("pcb version not supported")
- if version==3:
- Edge_Cuts_lvl=28
- Top_lvl=15
- if version>=4:
- Edge_Cuts_lvl=44
- Top_lvl=0
+ if version == 3:
+ Edge_Cuts_lvl = 28
+ Top_lvl = 15
+ if version >= 4:
+ Edge_Cuts_lvl = 44
+ Top_lvl = 0
# say(Kicad_Board)
- modified = ''
- j = 0; txt = ''; start = 0; s=0; prev_char="_"
- closing_char=""
- #say (len(Kicad_Board_elaborated))
+ modified = ""
+ j = 0
+ txt = ""
+ start = 0
+ s = 0
+ prev_char = "_"
+ closing_char = ""
+ # say (len(Kicad_Board_elaborated))
for i in Kicad_Board_elaborated[1:]:
if i in ['"', "'"] and s == 0:
- closing_char=i
- if prev_char!="\\":
+ closing_char = i
+ if prev_char != "\\":
s = 1
elif i in [closing_char] and s == 1:
- if prev_char!="\\":
+ if prev_char != "\\":
s = 0
if s == 0:
- if i == '(':
+ if i == "(":
j += 1
start = 1
- elif i == ')':
+ elif i == ")":
j -= 1
txt += i
- prev_char=i
+ prev_char = i
if j == 0 and start == 1:
- modified += '[start]' + txt.strip() + '[stop]'
- txt = ''
+ modified += "[start]" + txt.strip() + "[stop]"
+ txt = ""
start = 0
- #say(len(modified))
- #stop #maui
- layers = re.search(r'\[start\]\(layers(.+?)\)\[stop\]', modified, re.MULTILINE|re.DOTALL).group(0)
- for k in re.findall(r'\((.*?) (.*?) .*?\)', layers):
+ # say(len(modified))
+ # stop #maui
+ layers = re.search(r"\[start\]\(layers(.+?)\)\[stop\]", modified, re.MULTILINE | re.DOTALL).group(0)
+ for k in re.findall(r"\((.*?) (.*?) .*?\)", layers):
Levels[k[1]] = int(k[0])
- if Levels[k[1]] == Edge_Cuts_lvl: ##Edge.Cuts pcb version 4
- #myfile3.write(str(k)[8:-2])
- pcbEdgeName=str(k)[8:-2]
+ if Levels[k[1]] == Edge_Cuts_lvl: ##Edge.Cuts pcb version 4
+ # myfile3.write(str(k)[8:-2])
+ str(k)[8:-2]
if save_temp_data:
home = expanduser("~")
- t2_name=home+os.sep+'testM.txt'
- #f = __builtin__.open(t2_name,'w')
- #f = builtin.open(t2_name,'wb') #py2
- f = builtin.open(t2_name,'w') #p3
- f.write(modified) # python will convert \n to os.linesep
- f.close() # you can omit in most cases as the destructor will call it
- return modified,Levels,Edge_Cuts_lvl,Top_lvl,version,pcbThickness
+ t2_name = home + os.sep + "testM.txt"
+ # f = __builtin__.open(t2_name,'w')
+ # f = builtin.open(t2_name,'wb') #py2
+ with builtin.open(t2_name, "w") as f: # p3
+ f.write(modified) # python will convert \n to os.linesep
+ return modified, Levels, Edge_Cuts_lvl, Top_lvl, version, pcbThickness
+
+
### end Elaborate_Kicad_Board
-def get3DParams (mdl_name,params,rot, virtual):
- ''' list of single 3D model with parameters
- '''
+
+def get3DParams(mdl_name, params, rot, virtual):
+ """list of single 3D model with parameters"""
global addVirtual
-
- rotz_vrml_m = re.findall(r'\(rotate.*$', params) #bug on multiple model per footprint wrl, step sequence !!!
- #sayw(rotz_vrml_m);sayw("here")
- rotz=''
+
+ rotz_vrml_m = re.findall(r"\(rotate.*$", params) # bug on multiple model per footprint wrl, step sequence !!!
+ # sayw(rotz_vrml_m);sayw("here")
+ rotz = ""
if rotz_vrml_m:
- rotz_vrml=rotz_vrml_m[0].lstrip('(rotate').lstrip(' ')
- #say('rotation ');sayw(rotz_vrml)#;
- rotz=rotz_vrml
- #rotz=rotz.lstrip('(rotate')
- #rotz=rotz[13:-1]
- rotz=rotz[5:]
- #sayw("rotz:"+rotz)
- #stop
- #say("rotz:"+rotz)
- temp=rotz.split(" ")
- #say("rotz temp:"+temp[2])
- rotz=temp[2]
- rotx=temp[0]
- roty=temp[1]
- #warn=None
- warn=""
+ rotz_vrml = rotz_vrml_m[0].lstrip("(rotate").lstrip(" ")
+ # say('rotation ');sayw(rotz_vrml)#;
+ rotz = rotz_vrml
+ # rotz=rotz.lstrip('(rotate')
+ # rotz=rotz[13:-1]
+ rotz = rotz[5:]
+ # sayw("rotz:"+rotz)
+ # stop
+ # say("rotz:"+rotz)
+ temp = rotz.split(" ")
+ # say("rotz temp:"+temp[2])
+ rotz = temp[2]
+ temp[0]
+ temp[1]
+ # warn=None
+ warn = ""
# if float(rotx)!=0:
# warn=("rx ")
# if float(roty)!=0:
# warn+=("ry ")
- #if warn:
+ # if warn:
# sayw(warn)
- #say("rotate vrml: "+rotz)
- else:
- rotz_vrml_m="(xyz 0 0 0"
- if rotz=='':
- rotz=0.0
+ # say("rotate vrml: "+rotz)
else:
- rotz=float(rotz)
- rot_comb=rot-rotz #adding vrml module z-rotation
- #re.findall(r'\(rotate\s+(.+?)\)', i)
- pos_vrml_m = re.findall(r'\(at\s\(xyz\s+(.+?)\)', params)
- pos_vrml=pos_vrml_m[0] #len(model_list)-j-1] #bug on multiple model per footprint
- #if pos_vrml:
+ rotz_vrml_m = "(xyz 0 0 0"
+ rotz = 0.0 if rotz == "" else float(rotz)
+ rot_comb = rot - rotz # adding vrml module z-rotation
+ # re.findall(r'\(rotate\s+(.+?)\)', i)
+ pos_vrml_m = re.findall(r"\(at\s\(xyz\s+(.+?)\)", params)
+ pos_vrml = pos_vrml_m[0] # len(model_list)-j-1] #bug on multiple model per footprint
+ # if pos_vrml:
# say('pos ');sayw(pos_vrml)#;
- #say(i)
- scale_vrml_m = re.findall(r'\(scale\s\(xyz\s+(.+?)\)', params)
- scale_vrml=scale_vrml_m[0] #len(model_list)-j-1] #bug on multiple model per footprint
- error_scale_module=False
+ # say(i)
+ scale_vrml_m = re.findall(r"\(scale\s\(xyz\s+(.+?)\)", params)
+ scale_vrml = scale_vrml_m[0] # len(model_list)-j-1] #bug on multiple model per footprint
+ error_scale_module = False
if scale_vrml:
- #say('scale ');sayw(scale_vrml)#;
- #error_scale_module=False
- scale_vrml_vals=scale_vrml.split(" ")
- xsc_vrml_val=scale_vrml_vals[0]
- ysc_vrml_val=scale_vrml_vals[1]
- zsc_vrml_val=scale_vrml_vals[2]
+ # say('scale ');sayw(scale_vrml)#;
+ # error_scale_module=False
+ scale_vrml_vals = scale_vrml.split(" ")
+ xsc_vrml_val = scale_vrml_vals[0]
+ ysc_vrml_val = scale_vrml_vals[1]
+ zsc_vrml_val = scale_vrml_vals[2]
# if scale_vrml!='1 1 1':
- if float(xsc_vrml_val)!=1 or float(ysc_vrml_val)!=1 or float(zsc_vrml_val)!=1:
+ if float(xsc_vrml_val) != 1 or float(ysc_vrml_val) != 1 or float(zsc_vrml_val) != 1:
if "box_mcad" not in params and "cylV_mcad" not in params and "cylH_mcad" not in params:
- sayw('wrong scale!!! set scale to (1 1 1)')
- error_scale_module=True
- #model_list.append(mdl_name[0])
- #model=model_list[j]+'.wrl'
- model=mdl_name[0]+'.wrl'
+ sayw("wrong scale!!! set scale to (1 1 1)")
+ error_scale_module = True
+ # model_list.append(mdl_name[0])
+ # model=model_list[j]+'.wrl'
+ model = mdl_name[0] + ".wrl"
# if show_debug:
# sayerr(model_list)
# #stop
- if (virtual==1 and addVirtual==0):
- model_name='no3Dmodel'
- side='noLayer'
+ if virtual == 1 and addVirtual == 0:
+ model_name = "no3Dmodel"
if model:
- sayw("virtual model "+model+" skipped") #virtual found warning
+ sayw("virtual model " + model + " skipped") # virtual found warning
+ elif model:
+ # say (model.group(0))
+ # model_name=model.group(0)[6:]
+ # model_name=model[6:]
+ model_name = model
+ # sayw(model_name)
+ if "box_mcad" not in model_name and "cylV_mcad" not in model_name and "cylH_mcad" not in model_name:
+ if error_scale_module:
+ sayw("wrong scale!!! for " + model_name + " Set scale to (1 1 1)")
+ msg = """Error in '.kicad_pcb' model footprint
"""
+ msg += "
reset values of
" + model_name + "
to:
"
+ msg += "(scale (xyz 1 1 1))
"
+ warn += "reset values of scale to (xyz 1 1 1)"
+ ##reply = QtGui.QMessageBox.information(None,"info", msg)
+ # stop
+ # model_name=model_name[1:]
+ # say(model_name)
+ # sayw("here")
else:
- if model:
- # say (model.group(0))
- #model_name=model.group(0)[6:]
- #model_name=model[6:]
- model_name=model
- #sayw(model_name)
- if "box_mcad" not in model_name and "cylV_mcad" not in model_name and "cylH_mcad" not in model_name:
- if error_scale_module:
- sayw('wrong scale!!! for '+model_name+' Set scale to (1 1 1)')
- msg="""Error in '.kicad_pcb' model footprint
"""
- msg+="
reset values of
"+model_name+"
to:
"
- msg+="(scale (xyz 1 1 1))
"
- warn+=("reset values of scale to (xyz 1 1 1)")
- ##reply = QtGui.QMessageBox.information(None,"info", msg)
- #stop
- #model_name=model_name[1:]
- #say(model_name)
- #sayw("here")
- else:
- model_name='no3Dmodel'
- side='noLayer'
- #sayerr('no3Dmodel')
+ model_name = "no3Dmodel"
+ # sayerr('no3Dmodel')
return model_name, rot_comb, warn, pos_vrml, rotz_vrml, scale_vrml
+
+
###
+
def getPCBThickness(Board):
- #say(len(Kicad_Board))
- return float(re.findall(r'\(thickness (.+?)\)', Board)[0])
+ # say(len(Kicad_Board))
+ return float(re.findall(r"\(thickness (.+?)\)", Board)[0])
+
def getPCBVersion(Board):
- return int(re.findall(r'\(kicad_pcb \(version (.+?)\)', Board)[0])
+ return int(re.findall(r"\(kicad_pcb \(version (.+?)\)", Board)[0])
+
def getPCBArea(Kicad_Board):
- area = (re.findall(r'\(area (.+?)\)', Kicad_Board)[0])
+ return re.findall(r"\(area (.+?)\)", Kicad_Board)[0]
# say(area)
- return area
+
def createSolidBBox(model3D):
- selEx=model3D
+ selEx = model3D
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
if len(objs) == 1:
s = objs[0].Shape
- name=objs[0].Label
- FreeCAD.Console.PrintMessage(name+" name \r\n")
+ name = objs[0].Label
+ FreeCAD.Console.PrintMessage(name + " name \r\n")
# boundBox
boundBox_ = s.BoundBox
- boundBoxLX = boundBox_.XLength
- boundBoxLY = boundBox_.YLength
- boundBoxLZ = boundBox_.ZLength
a = str(boundBox_)
- a,b = a.split('(')
- c = b.split(',')
+ a, b = a.split("(")
+ c = b.split(",")
oripl_X = float(c[0])
oripl_Y = float(c[1])
oripl_Z = float(c[2])
- #say(str(boundBox_))
- #say("Rectangle : "+str(boundBox_.XLength)+" x "+str(boundBox_.YLength)+" x "+str(boundBox_.ZLength))
- #say("_____________________")
- #say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
- obj=FreeCAD.ActiveDocument.addObject('Part::Feature',name)
- obj.Shape=Part.makeBox(boundBox_.XLength, boundBox_.YLength, boundBox_.ZLength, FreeCAD.Vector(oripl_X,oripl_Y,oripl_Z), FreeCAD.Vector(0,0,1))
+ # say(str(boundBox_))
+ # say("Rectangle : "+str(boundBox_.XLength)+" x "+str(boundBox_.YLength)+" x "+str(boundBox_.ZLength))
+ # say("_____________________")
+ # say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
+ obj = FreeCAD.ActiveDocument.addObject("Part::Feature", name)
+ obj.Shape = Part.makeBox(
+ boundBox_.XLength,
+ boundBox_.YLength,
+ boundBox_.ZLength,
+ FreeCAD.Vector(oripl_X, oripl_Y, oripl_Z),
+ FreeCAD.Vector(0, 0, 1),
+ )
# Part.show(cube)
- #say("cube name "+ obj.Name)
+ # say("cube name "+ obj.Name)
else:
- FreeCAD.Console.PrintMessage("Select a single part object !"+"\r\n")
- #end bbox macro
- name=obj.Name
- #say("bbox name "+name)
- return name
+ FreeCAD.Console.PrintMessage("Select a single part object !" + "\r\n")
+ # end bbox macro
+ return obj.Name
+ # say("bbox name "+name)
del objs
-### end createSolidBBox
+ return None
+
+
+### end createSolidBBox
+
def findPcbCenter(pcbName):
pcb = FreeCAD.ActiveDocument.getObject(pcbName)
- s=pcb.Shape
- name=pcb.Label
+ s = pcb.Shape
# boundBox
boundBox_ = s.BoundBox
- boundBoxLX = boundBox_.XLength
- boundBoxLY = boundBox_.YLength
- boundBoxLZ = boundBox_.ZLength
center = s.BoundBox.Center
- #say(center)
- #say("["+str(center.x)+"],["+str(center.y)+"] center of pcb")
+ # say(center)
+ # say("["+str(center.x)+"],["+str(center.y)+"] center of pcb")
a = str(boundBox_)
- a,b = a.split('(')
- c = b.split(',')
- oripl_X = float(c[0])
- oripl_Y = float(c[1])
- oripl_Z = float(c[2])
- #say(str(boundBox_))
- #say("Rectangle : "+str(boundBox_.XLength)+" x "+str(boundBox_.YLength)+" x "+str(boundBox_.ZLength))
- #say("_____________________")
- #say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
- center_x=center.x; center_y=center.y
- bb_x=boundBox_.XLength; bb_y=boundBox_.YLength
+ a, b = a.split("(")
+ c = b.split(",")
+ float(c[0])
+ float(c[1])
+ float(c[2])
+ # say(str(boundBox_))
+ # say("Rectangle : "+str(boundBox_.XLength)+" x "+str(boundBox_.YLength)+" x "+str(boundBox_.ZLength))
+ # say("_____________________")
+ # say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
+ center_x = center.x
+ center_y = center.y
+ bb_x = boundBox_.XLength
+ bb_y = boundBox_.YLength
return center_x, center_y, bb_x, bb_y
+
+
### end findPcbCenter
-def getArc_minMax(xC,xA,yC,yA,alpha):
+
+def getArc_minMax(xC, xA, yC, yA, alpha):
# x1=xA start point; x2=xC center; xB end point; alpha=angle
global xMax, xmin, yMax, ymin
- j=0
- R=sqrt((xA-xC)**2+(yA-yC)**2)
- #say('R = '+str(R))
- if (xA>=xC) and (yAxC) and (yA= beta and ABeta <= pi/2:
- xB=R*sin(alpha+beta)+xC
- xMax=max(xB,xMax)
- xmin= min(xA,xmin)
- yB=yC-R*cos(alpha+beta)
- yMax= max(yB, yMax)
- ymin= min(yA, ymin)
- if ABeta >pi/2 and ABeta <=pi:
- xMax = max(R+xC,xMax)
- xB=R*sin(alpha+beta)+xC
+ R = sqrt((xA - xC) ** 2 + (yA - yC) ** 2)
+ # say('R = '+str(R))
+ if (xA >= xC) and (yA < yC):
+ beta = atan(abs(xA - xC) / abs(yA - yC))
+ ABeta = alpha + beta
+ # say(str(degrees(beta))+" beta "+ str(degrees(ABeta))+" ABeta")
+ # cases if (xA>xC) and (yA= beta and ABeta <= pi / 2:
+ xB = R * sin(alpha + beta) + xC
+ xMax = max(xB, xMax)
+ xmin = min(xA, xmin)
+ yB = yC - R * cos(alpha + beta)
+ yMax = max(yB, yMax)
+ ymin = min(yA, ymin)
+ if ABeta > pi / 2 and ABeta <= pi:
+ xMax = max(R + xC, xMax)
+ xB = R * sin(alpha + beta) + xC
xmin = min(xA, xB, xmin)
# yB = yC+R*cos(pi-(alpha+beta))
- yB=yC-R*cos(alpha+beta)
+ yB = yC - R * cos(alpha + beta)
yMax = max(yB, yMax)
ymin = min(yA, ymin)
- if ABeta >pi and ABeta <=3/2*pi:
- xB=R*sin(alpha+beta)+xC
- xMax=max(R+xC,xMax)
- xmin = min(xB,xmin)
- yB=yC-R*cos(alpha+beta)
- yMax = max(yC+R, yMax)
+ if ABeta > pi and ABeta <= 3 / 2 * pi:
+ xB = R * sin(alpha + beta) + xC
+ xMax = max(R + xC, xMax)
+ xmin = min(xB, xmin)
+ yB = yC - R * cos(alpha + beta)
+ yMax = max(yC + R, yMax)
ymin = min(yA, ymin)
- if ABeta >3/2*pi and ABeta <= 2*pi:
- xB=R*sin(alpha+beta)+xC
- xMax=max(R+xC,xMax)
- xmin = min(xC-R,xmin)
- yB=yC-R*cos(alpha+beta)
- yMax = max(yC+R, yMax)
+ if ABeta > 3 / 2 * pi and ABeta <= 2 * pi:
+ xB = R * sin(alpha + beta) + xC
+ xMax = max(R + xC, xMax)
+ xmin = min(xC - R, xmin)
+ yB = yC - R * cos(alpha + beta)
+ yMax = max(yC + R, yMax)
ymin = min(yA, yB, ymin)
- if ABeta >2*pi and ABeta <= 2*pi+beta:
- xmin = min(xC-R,xmin)
- xMax = max(R+xC,xMax)
- ymin = min(yC-R, ymin)
- yMax = max(yC+R, yMax)
- if (xA>xC) and (yA>=yC):
- beta=atan(abs(yA-yC)/abs(xA-xC))
- j=2; ABeta=(alpha+beta)
- #say(str(degrees(beta))+" beta "+ str(degrees(ABeta))+" ABeta")
- yB=yC+R*sin(ABeta)
- xB=xC+R*cos(ABeta)
- if ABeta >= beta and ABeta <= pi/2:
- xMax=max(xA,xMax)
- xmin= min(xB,xmin)
- yMax= max(yB, yMax)
- ymin= min(yA, ymin)
- if ABeta > pi/2 and ABeta <= pi:
- xmin= min(xB,xmin)
- xMax=max(xA,xMax)
- ymin= min(yA, yB, ymin)
- yMax= max(yC+R, yMax)
- if ABeta > pi and ABeta <= 3/2*pi:
- xmin= min(xC-R,xmin)
- xMax=max(xA,xMax)
- ymin= min(yB, ymin)
- yMax= max(yC+R, yMax)
- if ABeta > 3/2*pi and ABeta <= 2*pi:
- xmin= min(xC-R,xmin)
- xMax= max(xA,xB,xMax)
- ymin= min(yC-R, ymin)
- yMax= max(yC+R, yMax)
- if ABeta > 2*pi and ABeta <= beta+2*pi:
- xmin= min(xC-R,xmin)
- xMax= max(xC+R,xMax)
- ymin= min(yC-R, ymin)
- yMax= max(yC+R, yMax)
- if (xA<=xC) and (yA>yC):
- beta=atan(abs(xA-xC)/abs(yA-yC))
- j=3; ABeta=(alpha+beta)
- #say(str(degrees(beta))+" beta "+ str(degrees(ABeta))+" ABeta")
- yB=yC+R*cos(ABeta)
- xB=xC-R*sin(ABeta)
- if ABeta >= beta and ABeta <= pi/2:
- xMax= max(xA,xMax)
- xmin= min(xB,xmin)
- yMax= max(yA, yMax)
- ymin= min(yB, ymin)
- if ABeta > pi/2 and ABeta <= pi:
- xmin= min(xC-R,xmin)
- xMax= max(xA,xB,xMax)
- ymin= min(yB,ymin)
- yMax= max(yA,yMax)
- if ABeta > pi and ABeta <= 3/2*pi:
- xmin= min(xC-R,xmin)
- xMax= max(xB,xMax)
- ymin= min(yC-R, ymin)
- yMax= max(yA, yMax)
- if ABeta > 3/2*pi and ABeta <= 2*pi:
- xmin= min(xC-R,xmin)
- xMax= max(xC+R,xMax)
- ymin= min(yC-R, ymin)
- yMax= max(yA,yB, yMax)
- if ABeta > 2*pi and ABeta <= beta+2*pi:
- xmin= min(xC-R,xmin)
- xMax= max(xC+R,xMax)
- ymin= min(yC-R, ymin)
- yMax= max(yC+R, yMax)
- if (xA= beta and ABeta <= pi/2:
- xMax= max(xB,xMax)
- xmin= min(xA,xmin)
- yMax= max(yA, yMax)
- ymin= min(yB, ymin)
- if ABeta > pi/2 and ABeta <= pi:
- xmin= min(xA,xmin)
- xMax= max(xB,xMax)
- ymin= min(yC-R,ymin)
- yMax= max(yA,yB,yMax)
- if ABeta > pi and ABeta <= 3/2*pi:
- xmin= min(xA,xmin)
- xMax= max(xC+R,xMax)
- ymin= min(yC-R, ymin)
- yMax= max(yB, yMax)
- if ABeta > 3/2*pi and ABeta <= 2*pi:
- xmin= min(xA,xB,xmin)
- xMax= max(xC+R,xMax)
- ymin= min(yC-R,ymin)
- yMax= max(yC+R, yMax)
- if ABeta > 2*pi and ABeta <= beta+2*pi:
- xmin= min(xC-R,xmin)
- xMax= max(xC+R,xMax)
- ymin= min(yC-R, ymin)
- yMax= max(yC+R, yMax)
- #say(str(j)+" case j")
- #say('xC='+str(xC)+';yC='+str(yC)+';xA='+str(xA)+';yA='+str(yA))
- #print x1,x2,y1,y2
- #calculating xmin of arc
- R=sqrt((xA-xC)**2+(yA-yC)**2)
- #say('R = '+str(R))
- #say(str(xMax)+" xMax")
- #say(str(xmin)+" xmin")
+ if ABeta > 2 * pi and ABeta <= 2 * pi + beta:
+ xmin = min(xC - R, xmin)
+ xMax = max(R + xC, xMax)
+ ymin = min(yC - R, ymin)
+ yMax = max(yC + R, yMax)
+ if (xA > xC) and (yA >= yC):
+ beta = atan(abs(yA - yC) / abs(xA - xC))
+ ABeta = alpha + beta
+ # say(str(degrees(beta))+" beta "+ str(degrees(ABeta))+" ABeta")
+ yB = yC + R * sin(ABeta)
+ xB = xC + R * cos(ABeta)
+ if ABeta >= beta and ABeta <= pi / 2:
+ xMax = max(xA, xMax)
+ xmin = min(xB, xmin)
+ yMax = max(yB, yMax)
+ ymin = min(yA, ymin)
+ if ABeta > pi / 2 and ABeta <= pi:
+ xmin = min(xB, xmin)
+ xMax = max(xA, xMax)
+ ymin = min(yA, yB, ymin)
+ yMax = max(yC + R, yMax)
+ if ABeta > pi and ABeta <= 3 / 2 * pi:
+ xmin = min(xC - R, xmin)
+ xMax = max(xA, xMax)
+ ymin = min(yB, ymin)
+ yMax = max(yC + R, yMax)
+ if ABeta > 3 / 2 * pi and ABeta <= 2 * pi:
+ xmin = min(xC - R, xmin)
+ xMax = max(xA, xB, xMax)
+ ymin = min(yC - R, ymin)
+ yMax = max(yC + R, yMax)
+ if ABeta > 2 * pi and ABeta <= beta + 2 * pi:
+ xmin = min(xC - R, xmin)
+ xMax = max(xC + R, xMax)
+ ymin = min(yC - R, ymin)
+ yMax = max(yC + R, yMax)
+ if (xA <= xC) and (yA > yC):
+ beta = atan(abs(xA - xC) / abs(yA - yC))
+ ABeta = alpha + beta
+ # say(str(degrees(beta))+" beta "+ str(degrees(ABeta))+" ABeta")
+ yB = yC + R * cos(ABeta)
+ xB = xC - R * sin(ABeta)
+ if ABeta >= beta and ABeta <= pi / 2:
+ xMax = max(xA, xMax)
+ xmin = min(xB, xmin)
+ yMax = max(yA, yMax)
+ ymin = min(yB, ymin)
+ if ABeta > pi / 2 and ABeta <= pi:
+ xmin = min(xC - R, xmin)
+ xMax = max(xA, xB, xMax)
+ ymin = min(yB, ymin)
+ yMax = max(yA, yMax)
+ if ABeta > pi and ABeta <= 3 / 2 * pi:
+ xmin = min(xC - R, xmin)
+ xMax = max(xB, xMax)
+ ymin = min(yC - R, ymin)
+ yMax = max(yA, yMax)
+ if ABeta > 3 / 2 * pi and ABeta <= 2 * pi:
+ xmin = min(xC - R, xmin)
+ xMax = max(xC + R, xMax)
+ ymin = min(yC - R, ymin)
+ yMax = max(yA, yB, yMax)
+ if ABeta > 2 * pi and ABeta <= beta + 2 * pi:
+ xmin = min(xC - R, xmin)
+ xMax = max(xC + R, xMax)
+ ymin = min(yC - R, ymin)
+ yMax = max(yC + R, yMax)
+ if (xA < xC) and (yA <= yC):
+ beta = atan(abs(yA - yC) / abs(xA - xC))
+ ABeta = alpha + beta
+ # say(str(degrees(beta))+" beta "+ str(degrees(ABeta))+" ABeta")
+ yB = yC - R * sin(ABeta)
+ xB = xC - R * cos(ABeta)
+ if ABeta >= beta and ABeta <= pi / 2:
+ xMax = max(xB, xMax)
+ xmin = min(xA, xmin)
+ yMax = max(yA, yMax)
+ ymin = min(yB, ymin)
+ if ABeta > pi / 2 and ABeta <= pi:
+ xmin = min(xA, xmin)
+ xMax = max(xB, xMax)
+ ymin = min(yC - R, ymin)
+ yMax = max(yA, yB, yMax)
+ if ABeta > pi and ABeta <= 3 / 2 * pi:
+ xmin = min(xA, xmin)
+ xMax = max(xC + R, xMax)
+ ymin = min(yC - R, ymin)
+ yMax = max(yB, yMax)
+ if ABeta > 3 / 2 * pi and ABeta <= 2 * pi:
+ xmin = min(xA, xB, xmin)
+ xMax = max(xC + R, xMax)
+ ymin = min(yC - R, ymin)
+ yMax = max(yC + R, yMax)
+ if ABeta > 2 * pi and ABeta <= beta + 2 * pi:
+ xmin = min(xC - R, xmin)
+ xMax = max(xC + R, xMax)
+ ymin = min(yC - R, ymin)
+ yMax = max(yC + R, yMax)
+ # say(str(j)+" case j")
+ # say('xC='+str(xC)+';yC='+str(yC)+';xA='+str(xA)+';yA='+str(yA))
+ # print x1,x2,y1,y2
+ # calculating xmin of arc
+ R = sqrt((xA - xC) ** 2 + (yA - yC) ** 2)
+ # say('R = '+str(R))
+ # say(str(xMax)+" xMax")
+ # say(str(xmin)+" xmin")
# print xMax, xmin, yMax, ymin
# print pcbarcs[n]
- #print (pcbarcs[n][8:].split(' ')[0])
+ # print (pcbarcs[n][8:].split(' ')[0])
return 0
+
+
### end getArc_minMax
-def mid_point(prev_vertex,vertex,angle):
+
+def mid_point(prev_vertex, vertex, angle):
"""mid_point(prev_vertex,vertex,angle)-> mid_vertex
- returns mid point on arc of angle between prev_vertex and vertex"""
- angle=radians(angle/2)
- basic_angle=atan2(vertex.y-prev_vertex.y,vertex.x-prev_vertex.x)-pi/2
- shift=(1-cos(angle))*hypot(vertex.y-prev_vertex.y,vertex.x-prev_vertex.x)/2/sin(angle)
- midpoint=Base.Vector((vertex.x+prev_vertex.x)/2+shift*cos(basic_angle),(vertex.y+prev_vertex.y)/2+shift*sin(basic_angle),0)
- return midpoint
+ returns mid point on arc of angle between prev_vertex and vertex"""
+ angle = radians(angle / 2)
+ basic_angle = atan2(vertex.y - prev_vertex.y, vertex.x - prev_vertex.x) - pi / 2
+ shift = (1 - cos(angle)) * hypot(vertex.y - prev_vertex.y, vertex.x - prev_vertex.x) / 2 / sin(angle)
+ return Base.Vector(
+ (vertex.x + prev_vertex.x) / 2 + shift * cos(basic_angle),
+ (vertex.y + prev_vertex.y) / 2 + shift * sin(basic_angle),
+ 0,
+ )
+
+
###
-def Per_point(prev_vertex,vertex):
+
+def Per_point(prev_vertex, vertex):
"""Per_point(center,vertex)->per point
- returns opposite perimeter point of circle"""
- #basic_angle=atan2(prev_vertex.y-vertex.y,prev_vertex.x-vertex.x)
- #shift=hypot(prev_vertex.y-vertex.y,prev_vertex.x-vertex.x)
- #perpoint=Base.Vector(prev_vertex.x+shift*cos(basic_angle),prev_vertex.y+shift*sin(basic_angle),0)
- perpoint=Base.Vector(2*prev_vertex.x-vertex.x,2*prev_vertex.y-vertex.y,0)
- return perpoint
-###
+ returns opposite perimeter point of circle"""
+ # basic_angle=atan2(prev_vertex.y-vertex.y,prev_vertex.x-vertex.x)
+ # shift=hypot(prev_vertex.y-vertex.y,prev_vertex.x-vertex.x)
+ # perpoint=Base.Vector(prev_vertex.x+shift*cos(basic_angle),prev_vertex.y+shift*sin(basic_angle),0)
+ return Base.Vector(2 * prev_vertex.x - vertex.x, 2 * prev_vertex.y - vertex.y, 0)
+
+
+###
-#os.system("ps -C 'kicad-SteUp-tool' -o pid=|xargs kill -9")
+# os.system("ps -C 'kicad-SteUp-tool' -o pid=|xargs kill -9")
# UI Class definitions
##if _platform == "linux" or _platform == "linux2":
@@ -6094,14 +6567,15 @@ def Per_point(prev_vertex,vertex):
##elif _platform == "win32":
## # Windows
+
#####################################
-# Function infoDialog
+# Function infoDialog
#####################################
def infoDialog(msg):
- #QtGui.qFreeCAD.setOverrideCursor(QtCore.Qt.WaitCursor)
+ # QtGui.qFreeCAD.setOverrideCursor(QtCore.Qt.WaitCursor)
QtGui.qFreeCAD.restoreOverrideCursor()
QtGui.QApplication.restoreOverrideCursor()
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Information,u"Info Message",msg )
+ diag = QtGui.QMessageBox(QtGui.QMessageBox.Information, "Info Message", msg)
diag.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
diag.exec_()
QtGui.qFreeCAD.restoreOverrideCursor()
@@ -6109,8 +6583,8 @@ def infoDialog(msg):
## getAuxAxisOrigin
def getAuxAxisOrigin():
- match = re.search(r'\(aux_axis_origin (.+?) (.+?)\)', Kicad_Board)
- return [float(match.group(1)), float(match.group(2))];
+ match = re.search(r"\(aux_axis_origin (.+?) (.+?)\)", Kicad_Board)
+ return [float(match.group(1)), float(match.group(2))]
#####################################
@@ -6118,31 +6592,31 @@ def getAuxAxisOrigin():
#####################################
# Class definitions
+
# Function definitions
def onLoadFootprint(file_name=None):
- #name=QtGui.QFileDialog.getOpenFileName(this,tr("Open Image"), "/home/jana", tr("Image Files (*.png *.jpg *.bmp)"))[0]
- #global module_3D_dir
+ # name=QtGui.QFileDialog.getOpenFileName(this,tr("Open Image"), "/home/jana", tr("Image Files (*.png *.jpg *.bmp)"))[0]
+ # global module_3D_dir
global last_fp_path, test_flag, pt_lnx
global configParser, configFilePath, start_time
global ignore_utf8, ignore_utf8_incfg, disable_PoM_Observer
- #self.setGeometry(25, 250, 500, 500)
+ # self.setGeometry(25, 250, 500, 500)
clear_console()
- default_value='/'
- module_3D_dir=os.getenv('KISYS3DMOD', default_value)
- module_3D_dir=module_3D_dir+'/../'
+ default_value = "/"
+ module_3D_dir = os.getenv("KISYS3DMOD", default_value)
+ module_3D_dir = module_3D_dir + "/../"
## getting 3D models path
# say('KISYS3DMOD=')
- say('KISYS3DMOD='+os.getenv('KISYS3DMOD', default_value)+'\n'+'module_3D_dir='+module_3D_dir)
+ say("KISYS3DMOD=" + os.getenv("KISYS3DMOD", default_value) + "\n" + "module_3D_dir=" + module_3D_dir)
if not os.path.isdir(module_3D_dir):
- module_3D_dir="/"
- if last_fp_path=='':
- last_fp_path=module_3D_dir
+ module_3D_dir = "/"
+ if last_fp_path == "":
+ last_fp_path = module_3D_dir
if file_name is not None:
- #export_board_2step=True #for cmd line force exporting to STEP
- name=file_name
- elif test_flag==False:
- #if test_flag==False:
- Filter=""
+ # export_board_2step=True #for cmd line force exporting to STEP
+ name = file_name
+ elif not test_flag:
+ # if test_flag==False:
##if _platform == "darwin":
## ##workaround for OSX not opening native fileopen
## name=QtGui.QFileDialog.getOpenFileName(self, 'Open file',
@@ -6151,208 +6625,219 @@ def onLoadFootprint(file_name=None):
##else:
## name=QtGui.QFileDialog.getOpenFileName(self, "Open File...", last_file_path,
## "kicad module files (*.kicad_mod)")[0]
- #path = FreeCAD.ConfigGet("AppHomePath")
- #path = FreeCAD.ConfigGet("UserAppData")
- #path=last_file_path
- #try:
- # name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open File", last_file_path, "*.kicad_mod")#PySide
- #except Exception:
+ # path = FreeCAD.ConfigGet("AppHomePath")
+ # path = FreeCAD.ConfigGet("UserAppData")
+ # path=last_file_path
+ # try:
+ # name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open File", last_file_path, "*.kicad_mod")#PySide
+ # except Exception:
# FreeCAD.Console.PrintError("Error : " + str(name) + "\n")
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- #print('native_dlg',prefs_.GetBool('native_dlg'))
- if not(prefs_.GetBool('not_native_dlg')):
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open File...",
- make_unicode(last_fp_path), "*.kicad_mod")
+ # print('native_dlg',prefs_.GetBool('native_dlg'))
+ if not (prefs_.GetBool("not_native_dlg")):
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open File...",
+ make_unicode(last_fp_path),
+ "*.kicad_mod",
+ )
else:
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open File...",
- make_unicode(last_fp_path), "*.kicad_mod",options=QtWidgets.QFileDialog.DontUseNativeDialog)
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open File...",
+ make_unicode(last_fp_path),
+ "*.kicad_mod",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
else:
- name="C:/Cad/Progetti_K/ksu-test/test.kicad_mod"
+ name = "C:/Cad/Progetti_K/ksu-test/test.kicad_mod"
if len(name) > 0:
- #txtFile = __builtin__.open(name,"r")
- #with io.open(name,'r', encoding='utf-8') as txtFile:
- with codecs.open(name,'r', encoding='utf-8') as txtFile:
- #text = f.read()
- content = txtFile.readlines() # problems?
+ # txtFile = __builtin__.open(name,"r")
+ # with io.open(name,'r', encoding='utf-8') as txtFile:
+ with codecs.open(name, "r", encoding="utf-8") as txtFile:
+ # text = f.read()
+ content = txtFile.readlines() # problems?
## txtFile = __builtin__.open(name,"rb")
## content = txtFile.readlines()
- content.append(u" ")
- last_fp_path=os.path.dirname(txtFile.name)
+ content.append(" ")
+ last_fp_path = os.path.dirname(txtFile.name)
txtFile.close()
last_fp_path = re.sub("\\\\", "/", last_fp_path)
- #stop
+ # stop
ini_vars[11] = last_fp_path
##with __builtin__.open(configFilePath, 'wb') as configfile:
# configParser.write(configfile)
- #cfg_update_all()
+ # cfg_update_all()
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
pg.SetString("last_fp_path", make_string(last_fp_path))
- data=u''.join(content)
- #for item in content:
+ data = "".join(content)
+ # for item in content:
# data += item
- #print content; print data;stop
+ # print content; print data;stop
if ignore_utf8:
- content=re.sub(r'[^\x00-\x7F]+',' ', data) #workaround to remove utf8 extra chars
- sayw('removing utf-8 chars')
+ content = re.sub(r"[^\x00-\x7F]+", " ", data) # workaround to remove utf8 extra chars
+ sayw("removing utf-8 chars")
else:
- content=data
- #print content; stop
-
- #content=data
- #FreeCAD.Console.PrintMessage(content)
- #FreeCAD.Console.PrintMessage(data)
- FC_majorV=int(float(FreeCAD.Version()[0]))
- FC_minorV=int(float(FreeCAD.Version()[1]))
- say('FC Version '+str(FC_majorV)+str(FC_minorV))
+ content = data
+ # print content; stop
+
+ # content=data
+ # FreeCAD.Console.PrintMessage(content)
+ # FreeCAD.Console.PrintMessage(data)
+ FC_majorV = int(float(FreeCAD.Version()[0]))
+ FC_minorV = int(float(FreeCAD.Version()[1]))
+ say("FC Version " + str(FC_majorV) + str(FC_minorV))
if int(FC_majorV) <= 0 and int(FC_minorV) < 16:
- routineDrawFootPrint_old(content,name)
+ routineDrawFootPrint_old(content, name)
else:
if disable_VBO:
paramGetV = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View")
- VBO_status=paramGetV.GetBool("UseVBO")
- #sayerr("checking VBO")
- say("VBO status "+str(VBO_status))
+ VBO_status = paramGetV.GetBool("UseVBO")
+ # sayerr("checking VBO")
+ say("VBO status " + str(VBO_status))
if VBO_status:
- paramGetV.SetBool("UseVBO",False)
+ paramGetV.SetBool("UseVBO", False)
sayw("disabling VBO")
if disable_PoM_Observer:
- #paramGetPoM = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/PartOMagic")
- #PoMObs_status=paramGetPoM.GetBool("EnableObserver")
+ # paramGetPoM = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/PartOMagic")
+ # PoMObs_status=paramGetPoM.GetBool("EnableObserver")
PoMObs_status = False
if Observer.isRunning():
- PoMObs_status=True
- #if PoMObs_status:
+ PoMObs_status = True
+ # if PoMObs_status:
Observer.stop()
- # paramGetPoM.SetBool("EnableObserver",False)
+ # paramGetPoM.SetBool("EnableObserver",False)
sayw("disabling PoM Observer")
- routineDrawFootPrint(content,name)
- if (not pt_lnx): # and (not pt_osx): issue on AppImages hanging on loading
+ routineDrawFootPrint(content, name)
+ if not pt_lnx: # and (not pt_osx): issue on AppImages hanging on loading
FreeCADGui.SendMsgToActiveView("ViewFit")
else:
- zf= Timer (0.3,ZoomFitThread)
+ zf = Timer(0.3, ZoomFitThread)
zf.start()
- #zf= Timer (0.3,ZoomFitThread)
- #zf.start()
- if disable_VBO:
- if VBO_status:
- paramGetV.SetBool("UseVBO",True)
- sayw("enabling VBO")
- if disable_PoM_Observer:
- if PoMObs_status:
- Observer.start()
- # paramGetPoM.SetBool("EnableObserver",True)
- sayw("enabling PoM Observer")
- #txtFile.close()
+ # zf= Timer (0.3,ZoomFitThread)
+ # zf.start()
+ if disable_VBO and VBO_status:
+ paramGetV.SetBool("UseVBO", True)
+ sayw("enabling VBO")
+ if disable_PoM_Observer and PoMObs_status:
+ Observer.start()
+ # paramGetPoM.SetBool("EnableObserver",True)
+ sayw("enabling PoM Observer")
+ # txtFile.close()
+
+
###
+
def check_requirements():
# checking FC version requirement
######################################################################
- #say("FC Version ")
- #say(FreeCAD.Version())
+ # say("FC Version ")
+ # say(FreeCAD.Version())
global start_time, fusion, FC_export_min_version, use_AppPart, force_oldGroups, use_Links, use_LinkGroups
- FC_majorV,FC_minorV,FC_git_Nbr=getFCversion()
- #FC_majorV=FreeCAD.Version()[0]
- #FC_minorV=FreeCAD.Version()[1]
+ FC_majorV, FC_minorV, FC_git_Nbr = getFCversion()
+ # FC_majorV=FreeCAD.Version()[0]
+ # FC_minorV=FreeCAD.Version()[1]
##FC_majorV=int(FreeCAD.Version()[0])
##FC_minorV=int(FreeCAD.Version()[1])
- #try:
+ # try:
# FC_git_Nbr=int(FreeCAD.Version()[2].strip(" (Git)"))
- #except:
+ # except:
# FC_git_Nbr=0
- #FC_git_Nbr=(FreeCAD.Version()[2].strip(" (Git)"))
- sayw('FC Version '+str(FC_majorV)+str(FC_minorV)+"-"+str(FC_git_Nbr))
- msg1="use ONLY FreeCAD STABLE version 0.15 or later\r\n"
- #msg1+="to generate your STEP and VRML models\r\nFC 016 dev version results are still unpredictable"
- msg1+="to generate your STEP and VRML models\r\n"
- if int(FC_majorV) <= 0:
- if int(FC_minorV) < 15:
- QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Warning! ...",msg1)
- msg=''
- if FC_majorV == 0 and FC_minorV == 17:
- if FC_git_Nbr >= int(FC_export_min_version):
- use_AppPart=True
+ # FC_git_Nbr=(FreeCAD.Version()[2].strip(" (Git)"))
+ sayw("FC Version " + str(FC_majorV) + str(FC_minorV) + "-" + str(FC_git_Nbr))
+ msg1 = "use ONLY FreeCAD STABLE version 0.15 or later\r\n"
+ # msg1+="to generate your STEP and VRML models\r\nFC 016 dev version results are still unpredictable"
+ msg1 += "to generate your STEP and VRML models\r\n"
+ if int(FC_majorV) <= 0 and int(FC_minorV) < 15:
+ QtGui.QApplication.restoreOverrideCursor()
+ QtGui.QMessageBox.information(None, "Warning! ...", msg1)
+ msg = ""
+ if FC_majorV == 0 and FC_minorV == 17 and FC_git_Nbr >= int(FC_export_min_version):
+ use_AppPart = True
if FC_majorV > 0:
- use_AppPart=True
- if FC_majorV == 0 and FC_minorV > 17:
- if FC_git_Nbr >= int(FC_export_min_version):
- use_AppPart=True
+ use_AppPart = True
+ if FC_majorV == 0 and FC_minorV > 17 and FC_git_Nbr >= int(FC_export_min_version):
+ use_AppPart = True
if use_AppPart and not force_oldGroups:
sayw("creating hierarchy")
- if (fusion==True):
- msg+="you have chosen: fuse modules to board\r\nbe careful ... fusion can be heavy or generate FC crash"
- msg+="when fusing a lot of objects\r\nplease consider to use bbox or blacklist small objects\r\n\r\n"
+ if fusion:
+ msg += "you have chosen: fuse modules to board\r\nbe careful ... fusion can be heavy or generate FC crash"
+ msg += "when fusing a lot of objects\r\nplease consider to use bbox or blacklist small objects\r\n\r\n"
##start_time=current_milli_time()
+
+
###
def sanitizeSketch(s_name):
- ''' simplifying & sanitizing sketches '''
+ """simplifying & sanitizing sketches"""
global edge_tolerance, addConstraints
-
- s=FreeCAD.ActiveDocument.getObject(s_name)
- sayw('check to sanitize')
+
+ s = FreeCAD.ActiveDocument.getObject(s_name)
+ sayw("check to sanitize")
# print(s.TypeId)
- if 'Sketcher' in s.TypeId:
- idx_to_del=[]
- #print(s.Geometry)
- for i,g in enumerate (s.Geometry):
- #print(g,i)
+ if "Sketcher" in s.TypeId:
+ idx_to_del = []
+ # print(s.Geometry)
+ for i, g in enumerate(s.Geometry):
+ # print(g,i)
# g.length()
- #print('str(g)',str(g))
- if 'Line' in str(g):
- #print(g.length())
+ # print('str(g)',str(g))
+ if "Line" in str(g):
+ # print(g.length())
lng = distance(g.StartPoint, g.EndPoint)
- #print(lng)
+ # print(lng)
if lng <= edge_tolerance:
- print(g,i)
- sayw('too short')
- idx_to_del.append(i)
- if 'Circle' in str(g):
- if g.Radius <= edge_tolerance:
- print(g,i)
- sayw('too short')
+ print(g, i)
+ sayw("too short")
idx_to_del.append(i)
- if 'Arc' in str(g):
- #print('str(g)',str(g))
- #stop
+ if "Circle" in str(g) and g.Radius <= edge_tolerance:
+ print(g, i)
+ sayw("too short")
+ idx_to_del.append(i)
+ if "Arc" in str(g):
+ # print('str(g)',str(g))
+ # stop
lng = distance(g.StartPoint, g.EndPoint)
- #print(lng)
+ # print(lng)
if lng <= edge_tolerance:
- print(g,i)
- sayw('too short')
+ print(g, i)
+ sayw("too short")
idx_to_del.append(i)
- j=0
- if len(idx_to_del) >0 and addConstraints != 'none':
- sayw(u'sanitizing '+s.Label)
+ j = 0
+ if len(idx_to_del) > 0 and addConstraints != "none":
+ sayw("sanitizing " + s.Label)
for i in idx_to_del:
- s.delGeometry(i-j)
- j+=1
- # if len(idx_to_del) >0 and addConstraints!='none':
- tol1 = edge_tolerance #0.01
- constr1='coincident'
+ s.delGeometry(i - j)
+ j += 1
+ # if len(idx_to_del) >0 and addConstraints!='none':
+ tol1 = edge_tolerance # 0.01
+ constr1 = "coincident"
import constrainator
+
constrainator.add_constraints(s.Name, tol1, constr1)
- elif len(idx_to_del) >0 and addConstraints == 'none':
- sayerr(u'sanitizing skipped because of constraints=\'None\' in kSU settings')
+ elif len(idx_to_del) > 0 and addConstraints == "none":
+ sayerr("sanitizing skipped because of constraints='None' in kSU settings")
+
+
##
def add_constraints(s_name):
- """ adding coincident points constraints """
+ """adding coincident points constraints"""
global addConstraints, edge_tolerance
-
- s=FreeCAD.ActiveDocument.getObject(s_name)
-
- if hasattr(Part,"LineSegment"):
+
+ s = FreeCAD.ActiveDocument.getObject(s_name)
+
+ if hasattr(Part, "LineSegment"):
g_geom_points = {
Base.Vector: [1],
Part.LineSegment: [1, 2], # first point, last point
Part.Circle: [0, 3], # curve, center
Part.ArcOfCircle: [1, 2, 3], # first point, last point, center
- Part.BSplineCurve: [0,1,2,3], # for poles
- Part.ArcOfEllipse: [0,1,2,3], #
- Part.Ellipse: [0,1], #
- Part.ArcOfHyperbola: [0,1,2], #
- Part.Point: [0], #
+ Part.BSplineCurve: [0, 1, 2, 3], # for poles
+ Part.ArcOfEllipse: [0, 1, 2, 3],
+ Part.Ellipse: [0, 1],
+ Part.ArcOfHyperbola: [0, 1, 2],
+ Part.Point: [0],
}
else:
g_geom_points = {
@@ -6360,93 +6845,89 @@ def add_constraints(s_name):
Part.Line: [1, 2], # first point, last point
Part.Circle: [0, 3], # curve, center
Part.ArcOfCircle: [1, 2, 3], # first point, last point, center
- Part.BSplineCurve: [0,1,2,3], # for poles
- Part.ArcOfEllipse: [0,1,2,3], #
- Part.Ellipse: [0,1], #
- Part.ArcOfHyperbola: [0,1,2], #
- Part.Point: [0], #
+ Part.BSplineCurve: [0, 1, 2, 3], # for poles
+ Part.ArcOfEllipse: [0, 1, 2, 3],
+ Part.Ellipse: [0, 1],
+ Part.ArcOfHyperbola: [0, 1, 2],
+ Part.Point: [0],
}
- points=[]
- geoms=[]
- #print len((s.Geometry))
- #stop
- for geom_index in range(len((s.Geometry))):
+ geoms = []
+ # print len((s.Geometry))
+ # stop
+ for geom_index in range(len(s.Geometry)):
point_indexes = g_geom_points[type(s.Geometry[geom_index])]
- #sayerr(point_indexes), say (geom_index)
- #if 'Line' in type(PCB_Sketch.Geometry[geom_index]).__name__:
-
- if 'ArcOfCircle' in type(s.Geometry[geom_index]).__name__\
- or 'Line' in type(s.Geometry[geom_index]).__name__:
+ # sayerr(point_indexes), say (geom_index)
+ # if 'Line' in type(PCB_Sketch.Geometry[geom_index]).__name__:
+
+ if "ArcOfCircle" in type(s.Geometry[geom_index]).__name__ or "Line" in type(s.Geometry[geom_index]).__name__:
point1 = s.getPoint(geom_index, point_indexes[0])
- #sayerr(str(point1[0])+';'+str(point1[1]))
+ # sayerr(str(point1[0])+';'+str(point1[1]))
point2 = s.getPoint(geom_index, point_indexes[1])
- #sayw(str(point2[0])+';'+str(point1[1]))
- #points.append([[point1[0],point1[1]],[geom_index],[1]])
- #points.append([[point2[0],point2[1]],[geom_index],[2]])
- #points.append([[point1[0],point1[1]],[geom_index]]) #,[1]])
- #points.append([[point2[0],point2[1]],[geom_index]]) #,[2]])
- if 'Line' in type(s.Geometry[geom_index]).__name__:
- tp = 'Line'
- else:
- tp = 'Arc'
- geoms.append([point1[0],point1[1],point2[0],point2[1],tp])
- elif 'ArcOfEllipse' in type(s.Geometry[geom_index]).__name__:
+ # sayw(str(point2[0])+';'+str(point1[1]))
+ # points.append([[point1[0],point1[1]],[geom_index],[1]])
+ # points.append([[point2[0],point2[1]],[geom_index],[2]])
+ # points.append([[point1[0],point1[1]],[geom_index]]) #,[1]])
+ # points.append([[point2[0],point2[1]],[geom_index]]) #,[2]])
+ tp = "Line" if "Line" in type(s.Geometry[geom_index]).__name__ else "Arc"
+ geoms.append([point1[0], point1[1], point2[0], point2[1], tp])
+ elif "ArcOfEllipse" in type(s.Geometry[geom_index]).__name__:
point1 = s.getPoint(geom_index, point_indexes[1])
point2 = s.getPoint(geom_index, point_indexes[2])
- tp = 'Arc'
- geoms.append([point1[0],point1[1],point2[0],point2[1],tp])
+ tp = "Arc"
+ geoms.append([point1[0], point1[1], point2[0], point2[1], tp])
- #print points
+ # print points
def simu_distance(p0, p1):
- return max (abs(p0[0] - p1[0]), abs(p0[1] - p1[1]))
+ return max(abs(p0[0] - p1[0]), abs(p0[1] - p1[1]))
+
#
- #print geom
+ # print geom
sk_constraints = []
- cnt=1
- #print (addConstraints, ' constraints')
- #stop
- if addConstraints=='all':
+ cnt = 1
+ # print (addConstraints, ' constraints')
+ # stop
+ if addConstraints == "all":
for i, geo in enumerate(geoms):
- #for i in range(len(geom)):
- p_g0_0=[geo[0],geo[1]]
- p_g0_1=[geo[2],geo[3]]
- #print p_g0_0,pg_g0_1
- if abs(p_g0_0[0]-p_g0_1[0])< edge_tolerance and geo[4] == 'Line':
- #s.addConstraint(Sketcher.Constraint('Vertical',i))
- sk_constraints.append(Sketcher.Constraint('Vertical',i))
- elif abs(p_g0_0[1]-p_g0_1[1])< edge_tolerance and geo[4] == 'Line':
- #s.addConstraint(Sketcher.Constraint('Horizontal',i))
- sk_constraints.append(Sketcher.Constraint('Horizontal',i))
- j=i+1
- for geo2 in geoms[(i + 1):]:
- p_g1_0=[geo2[0],geo2[1]]
- p_g1_1=[geo2[2],geo2[3]]
- #rint p_g0_0, p_g0_1
- #rint p_g1_0, p_g1_1
- if distance(p_g0_0,p_g1_0)< edge_tolerance:
- ##App.ActiveDocument.PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',0,2,3,1))
- #s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,1))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,1,j,1))
- #print i,1,i+1,1
- elif distance(p_g0_0,p_g1_1)< edge_tolerance:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,2))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,1,j,2))
- #print i,1,i+1,2
- elif distance(p_g0_1,p_g1_0)< edge_tolerance:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,1))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,2,j,1))
- #print i,2,i+1,1
- elif distance(p_g0_1,p_g1_1)< edge_tolerance:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,2))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,2,j,2))
- #print i,2,i+1,2
- j=j+1
- cnt=cnt+1
- elif addConstraints=='coincident' or addConstraints=='full':
- if hasattr (FreeCAD.ActiveDocument.getObject(s_name), "autoconstraint"):
- sayw('using constrainator')
+ # for i in range(len(geom)):
+ p_g0_0 = [geo[0], geo[1]]
+ p_g0_1 = [geo[2], geo[3]]
+ # print p_g0_0,pg_g0_1
+ if abs(p_g0_0[0] - p_g0_1[0]) < edge_tolerance and geo[4] == "Line":
+ # s.addConstraint(Sketcher.Constraint('Vertical',i))
+ sk_constraints.append(Sketcher.Constraint("Vertical", i))
+ elif abs(p_g0_0[1] - p_g0_1[1]) < edge_tolerance and geo[4] == "Line":
+ # s.addConstraint(Sketcher.Constraint('Horizontal',i))
+ sk_constraints.append(Sketcher.Constraint("Horizontal", i))
+ j = i + 1
+ for geo2 in geoms[(i + 1) :]:
+ p_g1_0 = [geo2[0], geo2[1]]
+ p_g1_1 = [geo2[2], geo2[3]]
+ # rint p_g0_0, p_g0_1
+ # rint p_g1_0, p_g1_1
+ if distance(p_g0_0, p_g1_0) < edge_tolerance:
+ ##App.ActiveDocument.PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',0,2,3,1))
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,1))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 1, j, 1))
+ # print i,1,i+1,1
+ elif distance(p_g0_0, p_g1_1) < edge_tolerance:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,2))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 1, j, 2))
+ # print i,1,i+1,2
+ elif distance(p_g0_1, p_g1_0) < edge_tolerance:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,1))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 2, j, 1))
+ # print i,2,i+1,1
+ elif distance(p_g0_1, p_g1_1) < edge_tolerance:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,2))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 2, j, 2))
+ # print i,2,i+1,2
+ j = j + 1
+ cnt = cnt + 1
+ elif addConstraints in {"coincident", "full"}:
+ if hasattr(FreeCAD.ActiveDocument.getObject(s_name), "autoconstraint"):
+ sayw("using constrainator")
sanitizeSketch(s_name)
- sk1=FreeCAD.ActiveDocument.getObject(s_name)
+ sk1 = FreeCAD.ActiveDocument.getObject(s_name)
sk1.detectMissingPointOnPointConstraints(edge_tolerance)
sk1.makeMissingPointOnPointCoincident()
FreeCAD.activeDocument().recompute()
@@ -6454,66 +6935,67 @@ def simu_distance(p0, p1):
sk1.solve()
FreeCAD.activeDocument().recompute()
else:
- sayw('using old constrainator')
+ sayw("using old constrainator")
for i, geo in enumerate(geoms):
- #for i in range(len(geom)):
- #print (geo)
- #stop
- p_g0_0=[geo[0],geo[1]]
- p_g0_1=[geo[2],geo[3]]
- #print p_g0_0,pg_g0_1
- #if addConstraints=='all':
+ # for i in range(len(geom)):
+ # print (geo)
+ # stop
+ p_g0_0 = [geo[0], geo[1]]
+ p_g0_1 = [geo[2], geo[3]]
+ # print p_g0_0,pg_g0_1
+ # if addConstraints=='all':
# if abs(p_g0_0[0]-p_g0_1[0])< edge_tolerance:
# s.addConstraint(Sketcher.Constraint('Vertical',i))
# elif abs(p_g0_0[1]-p_g0_1[1])< edge_tolerance:
# s.addConstraint(Sketcher.Constraint('Horizontal',i))
- j=i+1
- for geo2 in geoms[(i + 1):]:
- p_g1_0=[geo2[0],geo2[1]]
- p_g1_1=[geo2[2],geo2[3]]
- #rint p_g0_0, p_g0_1
- #rint p_g1_0, p_g1_1
- if distance(p_g0_0,p_g1_0)< edge_tolerance:
- ##App.ActiveDocument.PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',0,2,3,1))
- #s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,1))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,1,j,1))
- #print i,1,i+1,1
- elif distance(p_g0_0,p_g1_1)< edge_tolerance:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,2))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,1,j,2))
- #print i,1,i+1,2
- elif distance(p_g0_1,p_g1_0)< edge_tolerance:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,1))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,2,j,1))
- #print i,2,i+1,1
- elif distance(p_g0_1,p_g1_1)< edge_tolerance:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,2))
- sk_constraints.append(Sketcher.Constraint('Coincident',i,2,j,2))
- #print i,2,i+1,2
- j=j+1
- cnt=cnt+1
+ j = i + 1
+ for geo2 in geoms[(i + 1) :]:
+ p_g1_0 = [geo2[0], geo2[1]]
+ p_g1_1 = [geo2[2], geo2[3]]
+ # rint p_g0_0, p_g0_1
+ # rint p_g1_0, p_g1_1
+ if distance(p_g0_0, p_g1_0) < edge_tolerance:
+ ##App.ActiveDocument.PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',0,2,3,1))
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,1))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 1, j, 1))
+ # print i,1,i+1,1
+ elif distance(p_g0_0, p_g1_1) < edge_tolerance:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,2))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 1, j, 2))
+ # print i,1,i+1,2
+ elif distance(p_g0_1, p_g1_0) < edge_tolerance:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,1))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 2, j, 1))
+ # print i,2,i+1,1
+ elif distance(p_g0_1, p_g1_1) < edge_tolerance:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,2))
+ sk_constraints.append(Sketcher.Constraint("Coincident", i, 2, j, 2))
+ # print i,2,i+1,2
+ j = j + 1
+ cnt = cnt + 1
if len(sk_constraints) > 0:
s.addConstraint(sk_constraints)
- #print 'counter ',cnt
- #print geo2
-
-###
+ # print 'counter ',cnt
+ # print geo2
+
+
+###
def add_missing_geo(s_name):
- """ adding missing geo on near but non coincident points"""
-
- s=FreeCAD.ActiveDocument.getObject(s_name)
-
- if hasattr(Part,"LineSegment"):
+ """adding missing geo on near but non coincident points"""
+
+ s = FreeCAD.ActiveDocument.getObject(s_name)
+
+ if hasattr(Part, "LineSegment"):
g_geom_points = {
Base.Vector: [1],
Part.LineSegment: [1, 2], # first point, last point
Part.Circle: [0, 3], # curve, center
Part.ArcOfCircle: [1, 2, 3], # first point, last point, center
- Part.BSplineCurve: [0,1,2,3], # for poles
- Part.ArcOfEllipse: [0,1,2,3], #
- Part.Ellipse: [0,1], #
- Part.ArcOfHyperbola: [0,1,2], #
- Part.Point: [0], #
+ Part.BSplineCurve: [0, 1, 2, 3], # for poles
+ Part.ArcOfEllipse: [0, 1, 2, 3],
+ Part.Ellipse: [0, 1],
+ Part.ArcOfHyperbola: [0, 1, 2],
+ Part.Point: [0],
}
else:
g_geom_points = {
@@ -6521,33 +7003,31 @@ def add_missing_geo(s_name):
Part.Line: [1, 2], # first point, last point
Part.Circle: [0, 3], # curve, center
Part.ArcOfCircle: [1, 2, 3], # first point, last point, center
- Part.BSplineCurve: [0,1,2,3], # for poles
- Part.ArcOfEllipse: [0,1,2,3], #
- Part.Ellipse: [0,1], #
- Part.ArcOfHyperbola: [0,1,2], #
- Part.Point: [0], #
+ Part.BSplineCurve: [0, 1, 2, 3], # for poles
+ Part.ArcOfEllipse: [0, 1, 2, 3],
+ Part.Ellipse: [0, 1],
+ Part.ArcOfHyperbola: [0, 1, 2],
+ Part.Point: [0],
}
- geo_points=[]
- geoms=[]
- #print len((s.Geometry))
- #stop
- for geom_index in range(len((s.Geometry))):
+ geoms = []
+ # print len((s.Geometry))
+ # stop
+ for geom_index in range(len(s.Geometry)):
point_indexes = g_geom_points[type(s.Geometry[geom_index])]
- #sayerr(point_indexes), say (geom_index)
- #if 'Line' in type(PCB_Sketch.Geometry[geom_index]).__name__:
- if 'ArcOfCircle' in type(s.Geometry[geom_index]).__name__\
- or 'Line' in type(s.Geometry[geom_index]).__name__:
+ # sayerr(point_indexes), say (geom_index)
+ # if 'Line' in type(PCB_Sketch.Geometry[geom_index]).__name__:
+ if "ArcOfCircle" in type(s.Geometry[geom_index]).__name__ or "Line" in type(s.Geometry[geom_index]).__name__:
point1 = s.getPoint(geom_index, point_indexes[0])
- #sayerr(str(point1[0])+';'+str(point1[1]))
+ # sayerr(str(point1[0])+';'+str(point1[1]))
point2 = s.getPoint(geom_index, point_indexes[1])
- #sayw(str(point2[0])+';'+str(point1[1]))
- #points.append([[point1[0],point1[1]],[geom_index],[1]])
- #points.append([[point2[0],point2[1]],[geom_index],[2]])
- #points.append([[point1[0],point1[1]],[geom_index]]) #,[1]])
- #points.append([[point2[0],point2[1]],[geom_index]]) #,[2]])
- #points.append([[point1[0],point1[1]],[geom_index]]) #,[1]])
- #geo_points.append([[point1[0],point1[1]],[point2[0],point2[1]],[geom_index]]) #,[2]])
- geoms.append([point1[0],point1[1],point2[0],point2[1]])
+ # sayw(str(point2[0])+';'+str(point1[1]))
+ # points.append([[point1[0],point1[1]],[geom_index],[1]])
+ # points.append([[point2[0],point2[1]],[geom_index],[2]])
+ # points.append([[point1[0],point1[1]],[geom_index]]) #,[1]])
+ # points.append([[point2[0],point2[1]],[geom_index]]) #,[2]])
+ # points.append([[point1[0],point1[1]],[geom_index]]) #,[1]])
+ # geo_points.append([[point1[0],point1[1]],[point2[0],point2[1]],[geom_index]]) #,[2]])
+ geoms.append([point1[0], point1[1], point2[0], point2[1]])
# elif 'ArcOfEllipse' in type(s.Geometry[geom_index]).__name__\
# or 'ArcOfHyperbola' in type(s.Geometry[geom_index]).__name__:
# point1 = s.getPoint(geom_index, point_indexes[1])
@@ -6558,104 +7038,108 @@ def add_missing_geo(s_name):
# elif 'Point' in type(s.Geometry[geom_index]).__name__:
# pass
sk_add_geo = []
- #say(geoms)
+ # say(geoms)
for i, geo in enumerate(geoms):
- p_g0_0=[geo[0],geo[1]]
- p_g0_1=[geo[2],geo[3]]
- j=i+1
- for geo2 in geoms[(i + 1):]:
- p_g2_0_0=[geo2[0],geo2[1]]
- p_g2_0_1=[geo2[2],geo2[3]]
- d = distance(p_g0_0,p_g2_0_0)
+ p_g0_0 = [geo[0], geo[1]]
+ p_g0_1 = [geo[2], geo[3]]
+ j = i + 1
+ for geo2 in geoms[(i + 1) :]:
+ p_g2_0_0 = [geo2[0], geo2[1]]
+ p_g2_0_1 = [geo2[2], geo2[3]]
+ d = distance(p_g0_0, p_g2_0_0)
if d < edge_tolerance and d > 0:
- sk_add_geo.append(PLine(Base.Vector(p_g0_0[0],p_g0_0[1],0), Base.Vector(p_g2_0_0[0],p_g2_0_0[1],0)))
- #print i,1,i+1,1
- d = distance(p_g0_1,p_g2_0_0)
- if d < edge_tolerance and d>0:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,2))
- sk_add_geo.append(PLine(Base.Vector(p_g0_1[0],p_g0_1[1],0), Base.Vector(p_g2_0_0[0],p_g2_0_0[1],0)))
- #print i,1,i+1,2
- d = distance(p_g0_0,p_g2_0_1)
- if d < edge_tolerance and d>0:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,1))
- sk_add_geo.append(PLine(Base.Vector(p_g0_0[0],p_g0_0[1],0), Base.Vector(p_g2_0_1[0],p_g2_0_1[1],0)))
- #print i,2,i+1,1
- d = distance(p_g0_1,p_g2_0_1)
- if d < edge_tolerance and d >0:
- #s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,2))
- sk_add_geo.append(PLine(Base.Vector(p_g0_1[0],p_g0_1[1],0), Base.Vector(p_g2_0_1[0],p_g2_0_1[1],0)))
- #print i,2,i+1,2
- j=j+1
- sayerr('added Geometry')
+ sk_add_geo.append(PLine(Base.Vector(p_g0_0[0], p_g0_0[1], 0), Base.Vector(p_g2_0_0[0], p_g2_0_0[1], 0)))
+ # print i,1,i+1,1
+ d = distance(p_g0_1, p_g2_0_0)
+ if d < edge_tolerance and d > 0:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,1,j,2))
+ sk_add_geo.append(PLine(Base.Vector(p_g0_1[0], p_g0_1[1], 0), Base.Vector(p_g2_0_0[0], p_g2_0_0[1], 0)))
+ # print i,1,i+1,2
+ d = distance(p_g0_0, p_g2_0_1)
+ if d < edge_tolerance and d > 0:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,1))
+ sk_add_geo.append(PLine(Base.Vector(p_g0_0[0], p_g0_0[1], 0), Base.Vector(p_g2_0_1[0], p_g2_0_1[1], 0)))
+ # print i,2,i+1,1
+ d = distance(p_g0_1, p_g2_0_1)
+ if d < edge_tolerance and d > 0:
+ # s.addConstraint(Sketcher.Constraint('Coincident',i,2,j,2))
+ sk_add_geo.append(PLine(Base.Vector(p_g0_1[0], p_g0_1[1], 0), Base.Vector(p_g2_0_1[0], p_g2_0_1[1], 0)))
+ # print i,2,i+1,2
+ j = j + 1
+ sayerr("added Geometry")
sayerr(sk_add_geo)
if len(sk_add_geo) > 0:
s.addGeometry(sk_add_geo)
-
-###
-
-def cpy_sketch(sname,nname=None):
- """ copy Sketch NB Geometry sequence is not conserved!!! """
-
- s=FreeCAD.ActiveDocument.getObject(sname)
- #geoL=len(App.ActiveDocument.getObject(sname).Geometry)
+
+
+###
+
+
+def cpy_sketch(sname, nname=None):
+ """copy Sketch NB Geometry sequence is not conserved!!!"""
+
+ FreeCAD.ActiveDocument.getObject(sname)
+ # geoL=len(App.ActiveDocument.getObject(sname).Geometry)
if nname is None:
- nname="Temp_Sketch"
- tsk= FreeCAD.activeDocument().addObject('Sketcher::SketchObject',nname)
+ nname = "Temp_Sketch"
+ tsk = FreeCAD.activeDocument().addObject("Sketcher::SketchObject", nname)
tsk.addGeometry(FreeCAD.ActiveDocument.getObject(sname).Geometry)
tsk.addConstraint(FreeCAD.ActiveDocument.getObject(sname).Constraints)
- tsk.Placement=FreeCAD.ActiveDocument.getObject(sname).Placement
- #print tsk.Geometry
+ tsk.Placement = FreeCAD.ActiveDocument.getObject(sname).Placement
+ # print tsk.Geometry
FreeCAD.ActiveDocument.recompute()
- #stop
+ # stop
return FreeCAD.ActiveDocument.ActiveObject.Name
-##
+
+
+##
+
def shift_sketch(sname, ofs, nname):
- """ shift Sketch Geometry (Geom sequence is not conserved!!!) """
-
- s1n=cpy_sketch(sname,nname)
+ """shift Sketch Geometry (Geom sequence is not conserved!!!)"""
+
+ s1n = cpy_sketch(sname, nname)
FreeCAD.ActiveDocument.recompute()
- s1=FreeCAD.ActiveDocument.getObject(s1n)
- lg=len (s1.Geometry)
- #print lg
- geo=[]
+ s1 = FreeCAD.ActiveDocument.getObject(s1n)
+ lg = len(s1.Geometry)
+ # print lg
+ geo = []
for k in range(lg):
geo.append(str(FreeCAD.ActiveDocument.getObject(s1.Name).Geometry[k]))
- #geo=FreeCAD.ActiveDocument.getObject(s1.Name).Geometry
+ # geo=FreeCAD.ActiveDocument.getObject(s1.Name).Geometry
for k in range(lg):
- FreeCAD.ActiveDocument.getObject(s1.Name).addCopy([k],FreeCAD.Vector(ofs[0],-ofs[1],0),False)
- #print FreeCAD.ActiveDocument.getObject(s1.Name).Geometry[k]
- #FreeCAD.ActiveDocument.getObject(s1.Name).delGeometry(k)
+ FreeCAD.ActiveDocument.getObject(s1.Name).addCopy([k], FreeCAD.Vector(ofs[0], -ofs[1], 0), False)
+ # print FreeCAD.ActiveDocument.getObject(s1.Name).Geometry[k]
+ # FreeCAD.ActiveDocument.getObject(s1.Name).delGeometry(k)
FreeCAD.ActiveDocument.recompute()
- #print len (s1.Geometry)
- #stop
- #print (s1.Geometry)
- nlg=len (s1.Geometry)
- idx_to_del=[]
- idx_to_del_str=[]
- #print geo
+ # print len (s1.Geometry)
+ # stop
+ # print (s1.Geometry)
+ nlg = len(s1.Geometry)
+ idx_to_del = []
+ # print geo
for k in range(nlg):
if str(FreeCAD.ActiveDocument.getObject(s1.Name).Geometry[k]) in geo:
idx_to_del.append(k)
- #for j in range (len(idx_to_del)):
+ # for j in range (len(idx_to_del)):
# idx_to_del_str.append(str(idx_to_del[j]))
- #print idx_to_del
- #stop
- #print idx_to_del_str
- for i in range (nlg-1,-1,-1):
- # #FreeCAD.ActiveDocument.getObject(s_name).delGeometry(k)
- #print i
+ # print idx_to_del
+ # stop
+ # print idx_to_del_str
+ for i in range(nlg - 1, -1, -1):
+ # #FreeCAD.ActiveDocument.getObject(s_name).delGeometry(k)
+ # print i
if i in idx_to_del:
FreeCAD.ActiveDocument.getObject(s1.Name).delGeometry(i)
FreeCAD.ActiveDocument.recompute()
- #FreeCAD.ActiveDocument.getObject(s1.Name).Placement = FreeCAD.Placement(FreeCAD.Vector(2*ofs[0],2*ofs[1],0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
-
- #geoL=len(App.ActiveDocument.getObject(sname).Geometry)
- #Temp_Sketch_Sft= FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Temp_Sketch_Sft')
- #geo=[]
- #for k in range(len (s.Geometry)):
+ # FreeCAD.ActiveDocument.getObject(s1.Name).Placement = FreeCAD.Placement(FreeCAD.Vector(2*ofs[0],2*ofs[1],0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
+
+ # geoL=len(App.ActiveDocument.getObject(sname).Geometry)
+ # Temp_Sketch_Sft= FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Temp_Sketch_Sft')
+ # geo=[]
+ # for k in range(len (s.Geometry)):
# App.ActiveDocument.Temp_Sketch_Sft.addCopy([k],App.Vector(100,100,0),False)
- #
+ #
# #if 'LineSegment' in type(s.Geometry[k]).__name__:
# ##if 'Line' in type(s.Geometry[k]).__name__:
# # #ls=''.format(s.Geometry[k].StartPoint.x+ofs[0],s.Geometry[k].StartPoint.y+ofs[1], s.Geometry[k].EndPoint.x+ofs[0],s.Geometry[k].EndPoint.y+ofs[1])
@@ -6666,345 +7150,392 @@ def shift_sketch(sname, ofs, nname):
# # spy=s.Geometry[k].StartPoint.y+ofs[1]
# # epx=s.Geometry[k].EndPoint.x+ofs[0]
# # epy=s.Geometry[k].EndPoint.y+ofs[1]
- # #
+ # #
# # FreeCAD.ActiveDocument.Temp_Sketch_Sft.addGeometry(PLine(Base.Vector(spx,spy,0), Base.Vector(epx,epy,0)))
- #
- #Temp_Sketch_Sft.Placement.Base[0]=FreeCAD.ActiveDocument.getObject(sname).Placement.Base[0]+ofs[0]
- #Temp_Sketch_Sft.Placement.Base[1]=FreeCAD.ActiveDocument.getObject(sname).Placement.Base[1]+ofs[1]
-
- #print Temp_Sketch.Geometry
- #FreeCAD.ActiveDocument.recompute()
+ #
+ # Temp_Sketch_Sft.Placement.Base[0]=FreeCAD.ActiveDocument.getObject(sname).Placement.Base[0]+ofs[0]
+ # Temp_Sketch_Sft.Placement.Base[1]=FreeCAD.ActiveDocument.getObject(sname).Placement.Base[1]+ofs[1]
+
+ # print Temp_Sketch.Geometry
+ # FreeCAD.ActiveDocument.recompute()
return FreeCAD.ActiveDocument.ActiveObject.Name
-##
+
+
+##
def PullPCB(file_name=None):
- onLoadBoard(None,False)
- #layer_list = ['Edge.Cuts','Dwgs.User','Eco1.User','Eco2.User']
- #LayerSelectionDlg = QtGui.QDialog()
- #ui = Ui_LayerSelection()
- #ui.setupUi(LayerSelectionDlg)
- #ui.comboBoxLayerSel.addItems(layer_list)
- #ui.label.setText("Select the layer to pull into the Sketch\nDefault \'Edge.Cuts\'")
- #reply=LayerSelectionDlg.exec_()
- #if reply==1: # ok
- # SketchLayer=str(ui.comboBoxLayerSel.currentText())
- # print(SketchLayer)
- #else:
- # print('Cancel')
+ onLoadBoard(None, False)
+
+
+# layer_list = ['Edge.Cuts','Dwgs.User','Eco1.User','Eco2.User']
+# LayerSelectionDlg = QtGui.QDialog()
+# ui = Ui_LayerSelection()
+# ui.setupUi(LayerSelectionDlg)
+# ui.comboBoxLayerSel.addItems(layer_list)
+# ui.label.setText("Select the layer to pull into the Sketch\nDefault \'Edge.Cuts\'")
+# reply=LayerSelectionDlg.exec_()
+# if reply==1: # ok
+# SketchLayer=str(ui.comboBoxLayerSel.currentText())
+# print(SketchLayer)
+# else:
+# print('Cancel')
##
+
def crc_gen(data):
import binascii
import re
-
- #data=u'Würfel'
- content=re.sub(r'[^\x00-\x7F]+','_', data)
- #make_unicode(hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
- #hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:].encode('utf-8')
- #print(data +u'_'+ hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
- return u'_'+ make_unicode(hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
+
+ # data=u'Würfel'
+ content = re.sub(r"[^\x00-\x7F]+", "_", data)
+ # make_unicode(hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
+ # hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:].encode('utf-8')
+ # print(data +u'_'+ hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
+ return "_" + make_unicode(hex(binascii.crc_hqx(content.encode("utf-8"), 0x0000))[2:])
+
+
##
def check_lightDir(set_default=False):
-
- pg=FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View")
+
+ pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View")
# pg.GetString('HeadlightDirection')
# FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View").SetString('HeadlightDirection','(-0.0,-0.0,-1.0)')
# pg.SetString('HeadlightDirection','(-0.299424,-0.0339817,-0.953515)')
- hld=pg.GetString('HeadlightDirection')
- if len(hld)>3:
- hx=float(hld.split(',')[0][1:])
- hy=float(hld.split(',')[1])
- hz=float(hld.split(',')[2][:-1])
- if (hx==0 and hy==0 and hz==-1 and set_default):
- pg.SetString('HeadlightDirection','(-0.3,0.3,-1.0)')
- #pg.SetString('HeadlightDirection','(0.2, -0.2, -1)')
- sayw('default light direction applied')
+ hld = pg.GetString("HeadlightDirection")
+ if len(hld) > 3:
+ hx = float(hld.split(",")[0][1:])
+ hy = float(hld.split(",")[1])
+ hz = float(hld.split(",")[2][:-1])
+ if hx == 0 and hy == 0 and hz == -1 and set_default:
+ pg.SetString("HeadlightDirection", "(-0.3,0.3,-1.0)")
+ # pg.SetString('HeadlightDirection','(0.2, -0.2, -1)')
+ sayw("default light direction applied")
else:
- say('light direction: '+hld)
- elif len(hld)==0:
- pg.SetString('HeadlightDirection','(-0.3,0.3,-1.0)')
- sayw('default light direction applied')
+ say("light direction: " + hld)
+ elif len(hld) == 0:
+ pg.SetString("HeadlightDirection", "(-0.3,0.3,-1.0)")
+ sayw("default light direction applied")
else:
pass
- #say('HeadlightDirection NOT defined') #pre FC0.22 02.2024
+ # say('HeadlightDirection NOT defined') #pre FC0.22 02.2024
+
+
##
-def onLoadBoard(file_name=None,load_models=None,insert=None):
- #name=QtGui.QFileDialog.getOpenFileName(this,tr("Open Image"), "/home/jana", tr("Image Files (*.png *.jpg *.bmp)"))[0]
- #global module_3D_dir
+def onLoadBoard(file_name=None, load_models=None, insert=None):
+ # name=QtGui.QFileDialog.getOpenFileName(this,tr("Open Image"), "/home/jana", tr("Image Files (*.png *.jpg *.bmp)"))[0]
+ # global module_3D_dir
global test_flag, last_pcb_path, configParser, configFilePath, start_time
global aux_orig, base_orig, base_point, idf_to_origin, off_x, off_y, export_board_2step
global real_board_pos_x, real_board_pos_y, board_base_point_x, board_base_point_y
- global models3D_prefix, models3D_prefix2, models3D_prefix3, models3D_prefix4,default_prefix3d
+ global models3D_prefix, models3D_prefix2, models3D_prefix3, models3D_prefix4, default_prefix3d
global blacklisted_model_elements, col, colr, colg, colb, whitelisted_3Dmodels
global bbox, volume_minimum, height_minimum, idf_to_origin, aux_orig
global base_orig, base_point, bbox_all, bbox_list, whitelisted_model_elements
global fusion, addVirtual, blacklisted_models, exportFusing, min_drill_size
global last_fp_path, last_pcb_path, plcmnt, xp, yp, exportFusing
- global ignore_utf8, ignore_utf8_incfg, pcb_path, disable_VBO, use_AppPart, force_oldGroups, use_Links, use_LinkGroups
+ global \
+ ignore_utf8, \
+ ignore_utf8_incfg, \
+ pcb_path, \
+ disable_VBO, \
+ use_AppPart, \
+ force_oldGroups, \
+ use_Links, \
+ use_LinkGroups
global original_filename, edge_width, load_sketch, grid_orig, warning_nbr, running_time, addConstraints
global conv_offs, zfit, fname_sfx, missingHeight, restore_specular_cls, preset_light
- import fcad_parser
- from fcad_parser import KicadPCB,SexpList
- import kicad_parser
objs_toberemoved = []
- ImportMode_status=0
+ ImportMode_status = 0
import_drawings = False
- objs_pre=[]
- doc=FreeCAD.ActiveDocument
+ objs_pre = []
+ doc = FreeCAD.ActiveDocument
if doc is not None:
- objs_pre=doc.Objects
-
+ objs_pre = doc.Objects
+
if preset_light:
check_lightDir(set_default=True)
pull_sketch = False
override_pcb = None
keep_pcb_sketch = None
- SketchLayer = 'Edge.Cuts' #None
+ SketchLayer = "Edge.Cuts" # None
if load_models is None:
load_models = True
- if load_models == False:
+ if not load_models:
# layer_list = ['Edge.Cuts','Dwgs.User','Cmts.User','Eco1.User','Eco2.User','Margin']
# layer_list = ['Edge.Cuts','Dwgs.User','Cmts.User','Eco1.User','Eco2.User','Margin', 'F.FillZone', 'F.KeepOutZone', 'F.MaskZone','B.FillZone', 'B.KeepOutZone', 'B.MaskZone',]
- layer_list = ['Edge.Cuts','Dwgs.User','Cmts.User','Eco1.User','Eco2.User','User.1','User.2','User.3','User.4','User.5','User.6','User.7','User.8','User.9','Margin', 'F.FillZone', 'F.KeepOutZone', 'F.MaskZone','B.FillZone', 'B.KeepOutZone', 'B.MaskZone',]
+ layer_list = [
+ "Edge.Cuts",
+ "Dwgs.User",
+ "Cmts.User",
+ "Eco1.User",
+ "Eco2.User",
+ "User.1",
+ "User.2",
+ "User.3",
+ "User.4",
+ "User.5",
+ "User.6",
+ "User.7",
+ "User.8",
+ "User.9",
+ "Margin",
+ "F.FillZone",
+ "F.KeepOutZone",
+ "F.MaskZone",
+ "B.FillZone",
+ "B.KeepOutZone",
+ "B.MaskZone",
+ ]
LayerSelectionDlg = QtGui.QDialog()
ui = Ui_LayerSelection()
ui.setupUi(LayerSelectionDlg)
ui.comboBoxLayerSel.addItems(layer_list)
if 0:
ui.comboBoxLayerSel.setEditable(True)
- ui.label.setText("Select the layer to pull into the Sketch\nDefault: \'Edge.Cuts\'")
- reply=LayerSelectionDlg.exec_()
- if reply==1: # ok
- SketchLayer=str(ui.comboBoxLayerSel.currentText())
+ ui.label.setText("Select the layer to pull into the Sketch\nDefault: 'Edge.Cuts'")
+ reply = LayerSelectionDlg.exec_()
+ if reply == 1: # ok
+ SketchLayer = str(ui.comboBoxLayerSel.currentText())
print(SketchLayer)
- if SketchLayer == 'Edge.Cuts':
- #override_pcb = ui.checkBox_replace.isChecked()
+ if SketchLayer == "Edge.Cuts":
+ # override_pcb = ui.checkBox_replace.isChecked()
if ui.radioBtn_replace_pcb.isChecked():
override_pcb = True
- elif ui.radioBtn_keep_sketch.isChecked(): #enabling keep sketch only if override is True
+ elif ui.radioBtn_keep_sketch.isChecked(): # enabling keep sketch only if override is True
override_pcb = True
keep_pcb_sketch = True
- else:
- if ui.radioBtn_replace_pcb.isChecked():
- import_drawings = True
+ elif ui.radioBtn_replace_pcb.isChecked():
+ import_drawings = True
pull_sketch = True
else:
- print('Cancel')
+ print("Cancel")
if pull_sketch or load_models:
- default_value='/'
clear_console()
- #lastPcb_dir='C:/Cad/Progetti_K/ksu-test'
- #say(lastPcb_dir+' last Pcb dir')
- #print(make_string(last_pcb_path))
- #print (make_unicode(last_pcb_path))
+ # lastPcb_dir='C:/Cad/Progetti_K/ksu-test'
+ # say(lastPcb_dir+' last Pcb dir')
+ # print(make_string(last_pcb_path))
+ # print (make_unicode(last_pcb_path))
if not os.path.isdir(make_unicode(last_pcb_path)):
- last_pcb_path=u"./"
- #say(last_pcb_path)
+ last_pcb_path = "./"
+ # say(last_pcb_path)
if file_name is not None:
- #export_board_2step=True #for cmd line force exporting to STEP
- name=file_name
- elif test_flag==False:
- Filter=""
- #minimize main window
- #self.setWindowState(QtCore.Qt.WindowMinimized)
- #infoDialog('ciao')
- #reply = QtGui.QInputDialog.getText(None, "Hello","Enter your thoughts for the day:")
- #if reply[1]:
+ # export_board_2step=True #for cmd line force exporting to STEP
+ name = file_name
+ elif not test_flag:
+ # self.setWindowState(QtCore.Qt.WindowMinimized)
+ # infoDialog('ciao')
+ # reply = QtGui.QInputDialog.getText(None, "Hello","Enter your thoughts for the day:")
+ # if reply[1]:
# # user clicked OK
# replyText = reply[0]
- #else:
+ # else:
# # user clicked Cancel
# replyText = reply[0] # which will be "" if they clicked Cancel
- #restore main window
- #self.setWindowState(QtCore.Qt.WindowActive)
+ # restore main window
+ # self.setWindowState(QtCore.Qt.WindowActive)
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if not(prefs_.GetBool('not_native_dlg')):
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open kicad PCB File...",
- make_unicode(last_pcb_path), "*.kicad_pcb")
+ if not (prefs_.GetBool("not_native_dlg")):
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open kicad PCB File...",
+ make_unicode(last_pcb_path),
+ "*.kicad_pcb",
+ )
else:
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open kicad PCB File...",
- make_unicode(last_pcb_path), "*.kicad_pcb",options=QtWidgets.QFileDialog.DontUseNativeDialog)
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open kicad PCB File...",
+ make_unicode(last_pcb_path),
+ "*.kicad_pcb",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
else:
- name="C:/Cad/Progetti_K/ksu-test/multidrill.kicad_pcb"
+ name = "C:/Cad/Progetti_K/ksu-test/multidrill.kicad_pcb"
if len(name) > 0:
if os.path.isfile(name):
- original_filename=name
- say('opening '+name)
- path, fname = os.path.split(name)
- fname=os.path.splitext(fname)[0]
- fname_sfx=crc_gen(make_unicode(fname))
- top_name='Top'+fname_sfx
- bot_name='Bot'+fname_sfx
- topV_name='TopV'+fname_sfx
- botV_name='BotV'+fname_sfx
- stepM_name='Step_Models'+fname_sfx
- stepV_name='Step_Virtual_Models'+fname_sfx
- pcb_name='Pcb'+fname_sfx
- sketch_name_sfx = 'PCB_Sketch'+fname_sfx
- board_name='Board'+fname_sfx
- boardG_name='Board_Geoms'+fname_sfx
- LCS_name = 'Local_CS'+fname_sfx
- #say(fname_sfx)
- #fpth = os.path.dirname(os.path.abspath(__file__))
+ original_filename = name
+ say("opening " + name)
+ _path, fname = os.path.split(name)
+ fname = os.path.splitext(fname)[0]
+ fname_sfx = crc_gen(make_unicode(fname))
+ top_name = "Top" + fname_sfx
+ bot_name = "Bot" + fname_sfx
+ topV_name = "TopV" + fname_sfx
+ botV_name = "BotV" + fname_sfx
+ stepM_name = "Step_Models" + fname_sfx
+ stepV_name = "Step_Virtual_Models" + fname_sfx
+ pcb_name = "Pcb" + fname_sfx
+ sketch_name_sfx = "PCB_Sketch" + fname_sfx
+ board_name = "Board" + fname_sfx
+ boardG_name = "Board_Geoms" + fname_sfx
+ LCS_name = "Local_CS" + fname_sfx
+ # say(fname_sfx)
+ # fpth = os.path.dirname(os.path.abspath(__file__))
fpth = os.path.dirname(os.path.abspath(name))
- #filePath = os.path.split(os.path.realpath(__file__))[0]
- say ('my file path '+fpth)
+ # filePath = os.path.split(os.path.realpath(__file__))[0]
+ say("my file path " + fpth)
if fpth == "":
- fpth = u"."
+ fpth = "."
last_pcb_path = fpth
- #last_pcb_path=path
- pcb_path=fpth
+ # last_pcb_path=path
+ pcb_path = fpth
# update existing value
- #say(default_ksu_msg)
- #stop
+ # say(default_ksu_msg)
+ # stop
last_pcb_path = re.sub("\\\\", "/", last_pcb_path)
# configParser.write(configfile)
##stop utf-8 test
ini_vars[10] = last_pcb_path
- #cfg_update_all()
+ # cfg_update_all()
test_import = False
- if override_pcb == True:
- insert=True
- if insert == True:
+ if override_pcb:
+ insert = True
+ if insert:
test_import = True
if test_import:
- doc=FreeCAD.ActiveDocument
+ doc = FreeCAD.ActiveDocument
if doc is None:
- doc=FreeCAD.newDocument(fname)
+ doc = FreeCAD.newDocument(fname)
override_pcb = False
- try:
+ with contextlib.suppress(BaseException):
doc.removeObject(LCS_name)
- except:
- pass
- elif override_pcb == True:
- if doc.getObject(boardG_name) in doc.Objects: #if 1: #try:
- if keep_pcb_sketch==True:
- #doc.getObject(boardG_name).removeObject(doc.getObject(sketch_name_sfx)) #keep sketck & constrains
+ elif override_pcb:
+ if doc.getObject(boardG_name) in doc.Objects: # if 1: #try:
+ if keep_pcb_sketch:
+ # doc.getObject(boardG_name).removeObject(doc.getObject(sketch_name_sfx)) #keep sketck & constrains
doc.getObject(boardG_name).ViewObject.dragObject(doc.getObject(sketch_name_sfx))
- #objs_toberemoved.append([doc.getObject(sketch_name_sfx)])
+ # objs_toberemoved.append([doc.getObject(sketch_name_sfx)])
removesubtree([doc.getObject(boardG_name)])
- #objs_toberemoved.append([doc.getObject(boardG_name)])
- #doc.recompute()
- try:
+ # objs_toberemoved.append([doc.getObject(boardG_name)])
+ # doc.recompute()
+ with contextlib.suppress(BaseException):
doc.removeObject(LCS_name)
- except:
- pass
- sayw('old Pcb removed')
- #stop
- else: #except:
+ sayw("old Pcb removed")
+ # stop
+ else: # except:
override_pcb = False
- say('Pcb not present')
+ say("Pcb not present")
+ elif import_drawings and FreeCAD.ActiveDocument is not None:
+ doc = FreeCAD.ActiveDocument
else:
- if import_drawings and FreeCAD.ActiveDocument is not None:
- doc=FreeCAD.ActiveDocument
- else:
- doc=FreeCAD.newDocument(fname)
+ doc = FreeCAD.newDocument(fname)
# doc.commitTransaction()
- doc.openTransaction('opening_kicad')
- say('opening Transaction \'opening_kicad\'')
+ doc.openTransaction("opening_kicad")
+ say("opening Transaction 'opening_kicad'")
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- pg.SetString("last_pcb_path", make_string(last_pcb_path)) # py3 .decode("utf-8")
- #pg.SetString("last_pcb_path", last_pcb_path.decode("utf-8"))
- modules=[]
- start_time=current_milli_time()
- #filename="C:/Cad/Progetti_K/D-can-term/can-term-test-fcad.kicad_pcb"
- #filename="c:\\Temp\\backpanel3.kicad_pcb"
- mypcb = KicadPCB.load(name) #test parser
- off_x=0; off_y=0 #offset of the board & modules
- grid_orig_warn=False
- aux_orig_warn=False
- if (grid_orig==1):
- #xp=getAuxAxisOrigin()[0]; yp=-getAuxAxisOrigin()[1] #offset of the board & modules
- if hasattr(mypcb, 'setup'):
- if hasattr(mypcb.setup, 'grid_origin'):
- #say('aux_axis_origin' + str(mypcb.setup.aux_axis_origin))
- xp=-mypcb.setup.grid_origin[0]; yp=mypcb.setup.grid_origin[1]
- sayw('grid origin found @ ('+str(xp)+', '+str(yp)+')')
+ pg.SetString("last_pcb_path", make_string(last_pcb_path)) # py3 .decode("utf-8")
+ # pg.SetString("last_pcb_path", last_pcb_path.decode("utf-8"))
+ modules = []
+ start_time = current_milli_time()
+ # filename="C:/Cad/Progetti_K/D-can-term/can-term-test-fcad.kicad_pcb"
+ # filename="c:\\Temp\\backpanel3.kicad_pcb"
+ mypcb = KicadPCB.load(name) # test parser
+ off_x = 0
+ off_y = 0 # offset of the board & modules
+ grid_orig_warn = False
+ aux_orig_warn = False
+ if grid_orig == 1:
+ # xp=getAuxAxisOrigin()[0]; yp=-getAuxAxisOrigin()[1] #offset of the board & modules
+ if hasattr(mypcb, "setup"):
+ if hasattr(mypcb.setup, "grid_origin"):
+ # say('aux_axis_origin' + str(mypcb.setup.aux_axis_origin))
+ xp = -mypcb.setup.grid_origin[0]
+ yp = mypcb.setup.grid_origin[1]
+ sayw("grid origin found @ (" + str(xp) + ", " + str(yp) + ")")
else:
- say('grid origin not set\nusing default top left corner')
- xp=0;yp=0
- grid_orig_warn=True
+ say("grid origin not set\nusing default top left corner")
+ xp = 0
+ yp = 0
+ grid_orig_warn = True
else:
- say('grid origin not set\nusing default top left corner')
- xp=0;yp=0
- grid_orig_warn=True
+ say("grid origin not set\nusing default top left corner")
+ xp = 0
+ yp = 0
+ grid_orig_warn = True
##off_x=-xp+xmin+(xMax-xmin)/2; off_y=-yp-(ymin+(yMax-ymin)/2) #offset of the board & modules
- #off_x=-xp+center_x;off_y=-yp+center_y
- off_x=-xp;off_y=-yp
- if (aux_orig==1):
- #xp=getAuxAxisOrigin()[0]; yp=-getAuxAxisOrigin()[1] #offset of the board & modules
- if hasattr(mypcb, 'setup'):
- if hasattr(mypcb.setup, 'aux_axis_origin'):
- #say('aux_axis_origin' + str(mypcb.setup.aux_axis_origin))
- sayw('aux origin found @: '+str(mypcb.setup.aux_axis_origin))
- xp=-mypcb.setup.aux_axis_origin[0]; yp=mypcb.setup.aux_axis_origin[1]
+ # off_x=-xp+center_x;off_y=-yp+center_y
+ off_x = -xp
+ off_y = -yp
+ if aux_orig == 1:
+ # xp=getAuxAxisOrigin()[0]; yp=-getAuxAxisOrigin()[1] #offset of the board & modules
+ if hasattr(mypcb, "setup"):
+ if hasattr(mypcb.setup, "aux_axis_origin"):
+ # say('aux_axis_origin' + str(mypcb.setup.aux_axis_origin))
+ sayw("aux origin found @: " + str(mypcb.setup.aux_axis_origin))
+ xp = -mypcb.setup.aux_axis_origin[0]
+ yp = mypcb.setup.aux_axis_origin[1]
else:
- aux_orig_warn=True
- say('aux origin not set')
- xp=-148.5;yp=98.5
+ aux_orig_warn = True
+ say("aux origin not set")
+ xp = -148.5
+ yp = 98.5
else:
- aux_orig_warn=True
- say('aux origin not set')
- xp=-148.5;yp=98.5
+ aux_orig_warn = True
+ say("aux origin not set")
+ xp = -148.5
+ yp = 98.5
##off_x=-xp+xmin+(xMax-xmin)/2; off_y=-yp-(ymin+(yMax-ymin)/2) #offset of the board & modules
- #off_x=-xp+center_x;off_y=-yp+center_y
- off_x=-xp;off_y=-yp
- #if (aux_orig==1):
+ # off_x=-xp+center_x;off_y=-yp+center_y
+ off_x = -xp
+ off_y = -yp
+ # if (aux_orig==1):
# #xp=getAuxAxisOrigin()[0]; yp=-getAuxAxisOrigin()[1] #offset of the board & modules
# if hasattr(mypcb.setup, 'aux_axis_origin'):
# #say('aux_axis_origin' + str(mypcb.setup.aux_axis_origin))
# xp=mypcb.setup.aux_axis_origin[0]; yp=-mypcb.setup.aux_axis_origin[1]
# else:
- # say('aux origin not used')
+ # say('aux origin not used')
# ##off_x=-xp+xmin+(xMax-xmin)/2; off_y=-yp-(ymin+(yMax-ymin)/2) #offset of the board & modules
# off_x=-xp+center_x;off_y=-yp+center_y
# #off_x=-xp;off_y=-yp
- modules,nsk = DrawPCB(mypcb,SketchLayer,override_pcb,keep_pcb_sketch)
- if override_pcb == True:
+ modules, nsk = DrawPCB(mypcb, SketchLayer, override_pcb, keep_pcb_sketch)
+ if override_pcb:
if use_AppPart and not force_oldGroups and not use_LinkGroups:
doc.getObject(board_name).addObject(doc.getObject(boardG_name))
elif use_LinkGroups:
- doc.getObject(board_name).ViewObject.dropObject(doc.getObject(boardG_name),doc.getObject(boardG_name),'',[])
- if SketchLayer == 'Edge.Cuts':
+ doc.getObject(board_name).ViewObject.dropObject(
+ doc.getObject(boardG_name),
+ doc.getObject(boardG_name),
+ "",
+ [],
+ )
+ if SketchLayer == "Edge.Cuts":
FreeCAD.ActiveDocument.getObject(board_name).Label = fname
- if hasattr(mypcb, 'general'):
- pcbThickness=float(mypcb.general.thickness)
- else:
- pcbThickness=1.6
+ pcbThickness = float(mypcb.general.thickness) if hasattr(mypcb, "general") else 1.6
## stop #test parser
check_requirements()
- #stop
- #pcbThickness,modules,board_elab,mod_lines,mod_arcs,mod_circles=LoadKicadBoard(name)
- #say(modules)
- #routineDrawPCB(pcbThickness,board_elab,mod_lines,mod_arcs,mod_circles)
+ # stop
+ # pcbThickness,modules,board_elab,mod_lines,mod_arcs,mod_circles=LoadKicadBoard(name)
+ # say(modules)
+ # routineDrawPCB(pcbThickness,board_elab,mod_lines,mod_arcs,mod_circles)
doc.commitTransaction()
- say('closing Transaction \'opening_kicad\'')
+ say("closing Transaction 'opening_kicad'")
else:
- say(name+' missing\r')
+ say(name + " missing\r")
stop
##Placing board at configured position
# pos objs x,-y
# pos board xm+(xM-xm)/2
- # pos board -(ym+(yM-ym)/2)
- if SketchLayer == 'Edge.Cuts':
- #center_x, center_y, bb_x, bb_y = findPcbCenter("Pcb")
- center_x, center_y, bb_x, bb_y = findPcbCenter(u"Pcb"+fname_sfx)
+ # pos board -(ym+(yM-ym)/2)
+ if SketchLayer == "Edge.Cuts":
+ # center_x, center_y, bb_x, bb_y = findPcbCenter("Pcb")
+ center_x, center_y, bb_x, bb_y = findPcbCenter("Pcb" + fname_sfx)
else:
- draw=FreeCAD.ActiveDocument.PCB_Sketch_draft
+ draw = FreeCAD.ActiveDocument.PCB_Sketch_draft
center_x, center_y, bb_x, bb_y = findPcbCenter(draw.Name)
## using PcbCenter
- xMax=center_x+bb_x/2
- xmin=center_x-bb_x/2
- yMax=center_y+bb_y/2
- ymin=center_y-bb_y/2
- #off_x=0; off_y=0 #offset of the board & modules
- if hasattr(mypcb, 'setup'):
- if hasattr(mypcb.setup, 'edge_width'): #maui edge width
- edge_width=mypcb.setup.edge_width
- elif hasattr(mypcb.setup, 'edge_cuts_line_width'): #maui edge cuts new width k 5.99
- edge_width=mypcb.setup.edge_cuts_line_width
- #if (grid_orig==1):
+ center_x + bb_x / 2
+ center_x - bb_x / 2
+ center_y + bb_y / 2
+ center_y - bb_y / 2
+ # off_x=0; off_y=0 #offset of the board & modules
+ if hasattr(mypcb, "setup"):
+ if hasattr(mypcb.setup, "edge_width"): # maui edge width
+ edge_width = mypcb.setup.edge_width
+ elif hasattr(mypcb.setup, "edge_cuts_line_width"): # maui edge cuts new width k 5.99
+ edge_width = mypcb.setup.edge_cuts_line_width
+ # if (grid_orig==1):
# #xp=getAuxAxisOrigin()[0]; yp=-getAuxAxisOrigin()[1] #offset of the board & modules
# if hasattr(mypcb.setup, 'grid_origin'):
# #say('aux_axis_origin' + str(mypcb.setup.aux_axis_origin))
@@ -7015,328 +7546,373 @@ def onLoadBoard(file_name=None,load_models=None,insert=None):
# ##off_x=-xp+xmin+(xMax-xmin)/2; off_y=-yp-(ymin+(yMax-ymin)/2) #offset of the board & modules
# #off_x=-xp+center_x;off_y=-yp+center_y
# off_x=-xp;off_y=-yp
- if (base_orig==1):
+ if base_orig == 1:
##off_x=xmin+(xMax-xmin)/2; off_y=-(ymin+(yMax-ymin)/2) #offset of the board & modules
- off_x=center_x;off_y=center_y
- #sayw(base_point);sayw(" base point")
- if (base_point==1):
+ off_x = center_x
+ off_y = center_y
+ # sayw(base_point);sayw(" base point")
+ if base_point == 1:
##off_x=-xp+xmin+(xMax-xmin)/2; off_y=-yp-(ymin+(yMax-ymin)/2) #offset of the board & modules
- #off_x=-xp+center_x;off_y=-yp+center_y
- off_x=-xp+center_x;off_y=-yp+center_y
- #sayw(off_x)
+ # off_x=-xp+center_x;off_y=-yp+center_y
+ off_x = -xp + center_x
+ off_y = -yp + center_y
+ # sayw(off_x)
## test maui board_base_point_x=(xMax-xmin)/2-off_x
## test maui board_base_point_y=-((yMax-ymin)/2)-off_y
- #real_board_pos_x=xmin+(xMax-xmin)/2
- #real_board_pos_y=-(ymin+(yMax-ymin)/2)
+ # real_board_pos_x=xmin+(xMax-xmin)/2
+ # real_board_pos_y=-(ymin+(yMax-ymin)/2)
## using PcbCenter
- real_board_pos_x=center_x
- real_board_pos_y=center_y
+ real_board_pos_x = center_x
+ real_board_pos_y = center_y
# doc = FreeCAD.ActiveDocument
- if idf_to_origin == True:
- board_base_point_x=-off_x
- board_base_point_y=-off_y
+ if idf_to_origin:
+ board_base_point_x = -off_x
+ board_base_point_y = -off_y
else:
- ## using PcbCenter
- say ('using PcbCenter')
- #board_base_point_x=xmin+(xMax-xmin)/2-off_x
- #board_base_point_y=-(ymin+(yMax-ymin)/2)-off_y
- board_base_point_x=center_x-off_x
- board_base_point_y=center_y-off_y
- sayw('placing board @ '+str(board_base_point_x)+','+str(board_base_point_y))
- if SketchLayer == 'Edge.Cuts':
- #FreeCAD.ActiveDocument.getObject("Pcb").Placement = FreeCAD.Placement(FreeCAD.Vector(board_base_point_x,board_base_point_y,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- FreeCAD.ActiveDocument.getObject(pcb_name).Placement = FreeCAD.Placement(FreeCAD.Vector(board_base_point_x,board_base_point_y,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- #else:
+ ## using PcbCenter
+ say("using PcbCenter")
+ # board_base_point_x=xmin+(xMax-xmin)/2-off_x
+ # board_base_point_y=-(ymin+(yMax-ymin)/2)-off_y
+ board_base_point_x = center_x - off_x
+ board_base_point_y = center_y - off_y
+ sayw("placing board @ " + str(board_base_point_x) + "," + str(board_base_point_y))
+ if SketchLayer == "Edge.Cuts":
+ # FreeCAD.ActiveDocument.getObject("Pcb").Placement = FreeCAD.Placement(FreeCAD.Vector(board_base_point_x,board_base_point_y,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
+ FreeCAD.ActiveDocument.getObject(pcb_name).Placement = FreeCAD.Placement(
+ FreeCAD.Vector(board_base_point_x, board_base_point_y, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0),
+ )
+ # else:
# draw.Placement = FreeCAD.Placement(FreeCAD.Vector(board_base_point_x,board_base_point_y,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- newname="PCB_Sketch"+fname_sfx
+ newname = "PCB_Sketch" + fname_sfx
if load_sketch:
- if SketchLayer != 'Edge.Cuts' and SketchLayer is not None:
- newname = SketchLayer.split('.')[0]+'_Sketch'
- say_inline('building up pcb time')
+ if SketchLayer != "Edge.Cuts" and SketchLayer is not None:
+ newname = SketchLayer.split(".")[0] + "_Sketch"
+ say_inline("building up pcb time")
get_time()
say(str(running_time))
- t1=(running_time)
- #add_constraints("PCB_Sketch_draft")
- #FreeCAD.ActiveDocument.recompute()
- if aux_orig==1 or grid_orig ==1:
- s_name=cpy_sketch("PCB_Sketch_draft",newname)
+ t1 = running_time
+ # add_constraints("PCB_Sketch_draft")
+ # FreeCAD.ActiveDocument.recompute()
+ if aux_orig == 1 or grid_orig == 1:
+ s_name = cpy_sketch("PCB_Sketch_draft", newname)
FreeCAD.ActiveDocument.recompute()
- #add_constraints(s_name)
- #say_time()
- #stop
- elif (base_point==1):
- s_name=shift_sketch("PCB_Sketch_draft", [-center_x,center_y],newname)
- #stop
- #add_constraints(s_name)
- FreeCAD.ActiveDocument.getObject(s_name).Placement = FreeCAD.Placement(FreeCAD.Vector(xp,yp,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- #say_time()
- elif (base_orig==1):
- s_name=shift_sketch("PCB_Sketch_draft", [-center_x,center_y],newname)
- #stop
- #add_constraints(s_name)
- FreeCAD.ActiveDocument.getObject(s_name).Placement = FreeCAD.Placement(FreeCAD.Vector(0,0,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- #say_time()
+ # add_constraints(s_name)
+ # say_time()
+ # stop
+ elif base_point == 1:
+ s_name = shift_sketch("PCB_Sketch_draft", [-center_x, center_y], newname)
+ # stop
+ # add_constraints(s_name)
+ FreeCAD.ActiveDocument.getObject(s_name).Placement = FreeCAD.Placement(
+ FreeCAD.Vector(xp, yp, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0),
+ )
+ # say_time()
+ elif base_orig == 1:
+ s_name = shift_sketch("PCB_Sketch_draft", [-center_x, center_y], newname)
+ # stop
+ # add_constraints(s_name)
+ FreeCAD.ActiveDocument.getObject(s_name).Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, 0, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0),
+ )
+ # say_time()
else:
- s_name=shift_sketch("PCB_Sketch_draft", [-center_x,center_y],newname)
- #stop
- #add_constraints(s_name)
- #sayerr('usebasepoint')
- #sayerr('usedefault')
- FreeCAD.ActiveDocument.getObject(s_name).Placement = FreeCAD.Placement(FreeCAD.Vector(center_x,center_y,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- #stop
- #say_time()
+ s_name = shift_sketch("PCB_Sketch_draft", [-center_x, center_y], newname)
+ # stop
+ # add_constraints(s_name)
+ # sayerr('usebasepoint')
+ # sayerr('usedefault')
+ FreeCAD.ActiveDocument.getObject(s_name).Placement = FreeCAD.Placement(
+ FreeCAD.Vector(center_x, center_y, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0),
+ )
+ # stop
+ # say_time()
# FreeCAD.ActiveDocument.removeObject("PCB_Sketch_draft")
objs_toberemoved.append([FreeCAD.ActiveDocument.getObject("PCB_Sketch_draft")])
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- if 0: # test_face # addConstraints!='none':
- say('start adding constraints to pcb sketch')
+ if 0: # test_face # addConstraints!='none':
+ say("start adding constraints to pcb sketch")
add_constraints(s_name)
get_time()
- #say('adding constraints time ' +str(running_time-t1))
- say('adding constraints time ' + "{0:.3f}".format(running_time-t1))
-
+ # say('adding constraints time ' +str(running_time-t1))
+ say("adding constraints time " + f"{running_time - t1:.3f}")
+
##FreeCAD.ActiveDocument.recompute()
- pcb_sk=FreeCAD.ActiveDocument.getObject(newname)
- gi = 0
- for g in pcb_sk.Geometry:
- if 'BSplineCurve object' in str(g):
+ pcb_sk = FreeCAD.ActiveDocument.getObject(newname)
+ for gi, g in enumerate(pcb_sk.Geometry):
+ if "BSplineCurve object" in str(g):
# say(str(g))
FreeCAD.ActiveDocument.getObject(newname).exposeInternalGeometry(gi)
- gi+=1
- if use_LinkGroups and SketchLayer == 'Edge.Cuts':
- FreeCAD.ActiveDocument.getObject(boardG_name).ViewObject.dropObject(FreeCAD.ActiveDocument.getObject(newname),FreeCAD.ActiveDocument.getObject(newname),'',[])
+ if use_LinkGroups and SketchLayer == "Edge.Cuts":
+ FreeCAD.ActiveDocument.getObject(boardG_name).ViewObject.dropObject(
+ FreeCAD.ActiveDocument.getObject(newname),
+ FreeCAD.ActiveDocument.getObject(newname),
+ "",
+ [],
+ )
FreeCADGui.Selection.clearSelection()
- sl = FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(newname))
- #FreeCADGui.runCommand('Std_HideSelection',0)
- FreeCADGui.runCommand('Std_ToggleVisibility',0)
+ FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(newname))
+ # FreeCADGui.runCommand('Std_HideSelection',0)
+ FreeCADGui.runCommand("Std_ToggleVisibility", 0)
FreeCADGui.Selection.clearSelection()
- #FreeCADGui.ActiveDocument.PCB_Sketch.Visibility = False
- #FreeCAD.ActiveDocument.getObject('PCB_Sketch').adjustRelativeLinks(FreeCAD.ActiveDocument.getObject('Board_Geoms'))
- elif SketchLayer == 'Edge.Cuts':
+ # FreeCADGui.ActiveDocument.PCB_Sketch.Visibility = False
+ # FreeCAD.ActiveDocument.getObject('PCB_Sketch').adjustRelativeLinks(FreeCAD.ActiveDocument.getObject('Board_Geoms'))
+ elif SketchLayer == "Edge.Cuts":
FreeCAD.ActiveDocument.getObject(boardG_name).addObject(pcb_sk)
-
- #updating pcb_sketch
- if SketchLayer != 'Edge.Cuts' and SketchLayer is not None:
+
+ # updating pcb_sketch
+ if SketchLayer != "Edge.Cuts" and SketchLayer is not None:
pcb_sk.Label = SketchLayer
if nsk > 1:
- pcb_sk.Label+="s"
- pcb_sk.ViewObject.Visibility=False
- #FreeCAD.ActiveDocument.getObject("PCB_Sketch").Placement = FreeCAD.Placement(FreeCAD.Vector(board_base_point_x,board_base_point_y,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- #FreeCAD.ActiveDocument.getObject("PCB_SketchN").Placement = FreeCAD.Placement(FreeCAD.Vector(board_base_point_x,board_base_point_y,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
+ pcb_sk.Label += "s"
+ pcb_sk.ViewObject.Visibility = False
+ # FreeCAD.ActiveDocument.getObject("PCB_Sketch").Placement = FreeCAD.Placement(FreeCAD.Vector(board_base_point_x,board_base_point_y,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
+ # FreeCAD.ActiveDocument.getObject("PCB_SketchN").Placement = FreeCAD.Placement(FreeCAD.Vector(board_base_point_x,board_base_point_y,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
## FreeCAD.ActiveDocument.getObject("Pcb").Placement = FreeCAD.Placement(FreeCAD.Vector(-off_x,-off_y,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- #ImportGui.insert(u"./c0603.step","demo_5D_vrml_from_step")
- if (not pt_lnx): # and (not pt_osx): issue on AppImages hanging on loading
+ # ImportGui.insert(u"./c0603.step","demo_5D_vrml_from_step")
+ if not pt_lnx: # and (not pt_osx): issue on AppImages hanging on loading
FreeCADGui.SendMsgToActiveView("ViewFit")
else:
- zf= Timer (0.1,ZoomFitThread)
+ zf = Timer(0.1, ZoomFitThread)
zf.start()
- if keep_pcb_sketch == True:
- #sayw(sketch_name_sfx+'001')
- if doc.getObject(sketch_name_sfx+'001') in doc.Objects: #if 1: #try:
- doc.removeObject(sketch_name_sfx+'001') #keep sketck & constrains
- #objs_toberemoved.append([doc.getObject(sketch_name_sfx+'001')])
- docG = FreeCADGui.ActiveDocument
- docG.getObject(sketch_name_sfx).Visibility=True
- elif override_pcb == True:
- if doc.getObject(sketch_name_sfx) in doc.Objects: #if 1: #try:
+ if keep_pcb_sketch:
+ # sayw(sketch_name_sfx+'001')
+ if doc.getObject(sketch_name_sfx + "001") in doc.Objects: # if 1: #try:
+ doc.removeObject(sketch_name_sfx + "001") # keep sketck & constrains
+ # objs_toberemoved.append([doc.getObject(sketch_name_sfx+'001')])
docG = FreeCADGui.ActiveDocument
- docG.getObject(sketch_name_sfx).Visibility=True
+ docG.getObject(sketch_name_sfx).Visibility = True
+ elif override_pcb and doc.getObject(sketch_name_sfx) in doc.Objects: # if 1: #try:
+ docG = FreeCADGui.ActiveDocument
+ docG.getObject(sketch_name_sfx).Visibility = True
if not pull_sketch or load_models:
if use_AppPart and not force_oldGroups and not use_LinkGroups:
- #sayw("creating hierarchy")
+ # sayw("creating hierarchy")
## to evaluate to add App::Part hierarchy
- doc.Tip = doc.addObject('App::Part',stepM_name)
+ doc.Tip = doc.addObject("App::Part", stepM_name)
stepM = doc.ActiveObject
stepM.Label = stepM_name
- doc.Tip = doc.addObject('App::Part',top_name)
+ doc.Tip = doc.addObject("App::Part", top_name)
topG = doc.ActiveObject
topG.Label = top_name
- doc.Tip = doc.addObject('App::Part',bot_name)
+ doc.Tip = doc.addObject("App::Part", bot_name)
botG = doc.ActiveObject
botG.Label = bot_name
doc.getObject(stepM_name).addObject(doc.getObject(top_name))
- doc.getObject(stepM_name).addObject(doc.getObject(bot_name))
+ doc.getObject(stepM_name).addObject(doc.getObject(bot_name))
try:
- doc.Step_Models.License = ''
- doc.Step_Models.LicenseURL = ''
+ doc.Step_Models.License = ""
+ doc.Step_Models.LicenseURL = ""
except:
pass
- #FreeCADGui.activeView().setActiveObject('Step_Models', doc.Step_Models)
+ # FreeCADGui.activeView().setActiveObject('Step_Models', doc.Step_Models)
doc.getObject(board_name).addObject(doc.getObject(stepM_name))
- doc.Tip = doc.addObject('App::Part',stepV_name)
+ doc.Tip = doc.addObject("App::Part", stepV_name)
stepV = doc.ActiveObject
stepV.Label = stepV_name
- doc.Tip = doc.addObject('App::Part',topV_name)
+ doc.Tip = doc.addObject("App::Part", topV_name)
topV = doc.ActiveObject
topV.Label = topV_name
- doc.Tip = doc.addObject('App::Part',botV_name)
+ doc.Tip = doc.addObject("App::Part", botV_name)
botV = doc.ActiveObject
botV.Label = botV_name
doc.getObject(stepV_name).addObject(doc.getObject(topV_name))
doc.getObject(stepV_name).addObject(doc.getObject(botV_name))
try:
- stepV.License = ''
- stepV.LicenseURL = ''
+ stepV.License = ""
+ stepV.LicenseURL = ""
except:
pass
FreeCADGui.activeView().setActiveObject(stepV_name, stepV)
doc.getObject(board_name).addObject(doc.getObject(stepV_name))
- doc.getObject(board_name).Label=fname
+ doc.getObject(board_name).Label = fname
try:
- doc.getObject(board_name).License=''
- doc.getObject(board_name).LicenseURL=''
+ doc.getObject(board_name).License = ""
+ doc.getObject(board_name).LicenseURL = ""
except:
pass
## end hierarchy
elif use_LinkGroups:
- doc.Tip = doc.addObject('App::LinkGroup',stepM_name)
- stepM=doc.ActiveObject
+ doc.Tip = doc.addObject("App::LinkGroup", stepM_name)
+ stepM = doc.ActiveObject
stepM.Label = stepM_name
- doc.Tip = doc.addObject('App::LinkGroup',stepV_name)
- stepV=doc.ActiveObject
+ doc.Tip = doc.addObject("App::LinkGroup", stepV_name)
+ stepV = doc.ActiveObject
stepV.Label = stepV_name
- doc.addObject('App::LinkGroup',top_name)
- topG=doc.ActiveObject
+ doc.addObject("App::LinkGroup", top_name)
+ topG = doc.ActiveObject
topG.Label = top_name
- doc.addObject('App::LinkGroup',bot_name)
- botG=doc.ActiveObject
+ doc.addObject("App::LinkGroup", bot_name)
+ botG = doc.ActiveObject
botG.Label = bot_name
- doc.addObject('App::LinkGroup',topV_name)
- topVG=doc.ActiveObject
+ doc.addObject("App::LinkGroup", topV_name)
+ topVG = doc.ActiveObject
topVG.Label = topV_name
- doc.addObject('App::LinkGroup',botV_name)
- botVG=doc.ActiveObject
+ doc.addObject("App::LinkGroup", botV_name)
+ botVG = doc.ActiveObject
botVG.Label = botV_name
- #doc.getObject('Top').adjustRelativeLinks(doc.getObject('Step_Models'))
- doc.getObject(stepM_name).ViewObject.dropObject(doc.getObject(top_name),doc.getObject(top_name),'',[])
- #doc.getObject('TopV').adjustRelativeLinks(doc.getObject('Step_Virtual_Models'))
- doc.getObject(stepV_name).ViewObject.dropObject(doc.getObject(topV_name),doc.getObject(topV_name),'',[])
- #doc.getObject('Bot').adjustRelativeLinks(doc.getObject('Step_Models'))
- doc.getObject(stepM_name).ViewObject.dropObject(doc.getObject(bot_name),doc.getObject(bot_name),'',[])
- #doc.getObject('BotV').adjustRelativeLinks(doc.getObject('Step_Virtual_Models'))
- doc.getObject(stepV_name).ViewObject.dropObject(doc.getObject(botV_name),doc.getObject(botV_name),'',[])
- #doc.getObject('Step_Models').adjustRelativeLinks(doc.getObject('Board'))
- doc.getObject(board_name).ViewObject.dropObject(doc.getObject(stepM_name),doc.getObject(stepM_name),'',[])
- #doc.getObject('Step_Virtual_Models').adjustRelativeLinks(doc.getObject('Board'))
- doc.getObject(board_name).ViewObject.dropObject(doc.getObject(stepV_name),doc.getObject(stepV_name),'',[])
+ # doc.getObject('Top').adjustRelativeLinks(doc.getObject('Step_Models'))
+ doc.getObject(stepM_name).ViewObject.dropObject(
+ doc.getObject(top_name),
+ doc.getObject(top_name),
+ "",
+ [],
+ )
+ # doc.getObject('TopV').adjustRelativeLinks(doc.getObject('Step_Virtual_Models'))
+ doc.getObject(stepV_name).ViewObject.dropObject(
+ doc.getObject(topV_name),
+ doc.getObject(topV_name),
+ "",
+ [],
+ )
+ # doc.getObject('Bot').adjustRelativeLinks(doc.getObject('Step_Models'))
+ doc.getObject(stepM_name).ViewObject.dropObject(
+ doc.getObject(bot_name),
+ doc.getObject(bot_name),
+ "",
+ [],
+ )
+ # doc.getObject('BotV').adjustRelativeLinks(doc.getObject('Step_Virtual_Models'))
+ doc.getObject(stepV_name).ViewObject.dropObject(
+ doc.getObject(botV_name),
+ doc.getObject(botV_name),
+ "",
+ [],
+ )
+ # doc.getObject('Step_Models').adjustRelativeLinks(doc.getObject('Board'))
+ doc.getObject(board_name).ViewObject.dropObject(
+ doc.getObject(stepM_name),
+ doc.getObject(stepM_name),
+ "",
+ [],
+ )
+ # doc.getObject('Step_Virtual_Models').adjustRelativeLinks(doc.getObject('Board'))
+ doc.getObject(board_name).ViewObject.dropObject(
+ doc.getObject(stepV_name),
+ doc.getObject(stepV_name),
+ "",
+ [],
+ )
FreeCADGui.Selection.clearSelection()
else:
- #sayerr("creating flat groups")
+ # sayerr("creating flat groups")
doc.addObject("App::DocumentObjectGroup", stepM_name)
doc.addObject("App::DocumentObjectGroup", stepV_name)
doc.recompute()
say_time()
if disable_VBO:
paramGetV = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/View")
- VBO_status=paramGetV.GetBool("UseVBO")
- #sayerr("checking VBO")
- say("VBO status "+str(VBO_status))
+ VBO_status = paramGetV.GetBool("UseVBO")
+ # sayerr("checking VBO")
+ say("VBO status " + str(VBO_status))
if VBO_status:
- paramGetV.SetBool("UseVBO",False)
+ paramGetV.SetBool("UseVBO", False)
sayw("disabling VBO")
- #stop
- #stop
+ # stop
+ # stop
if disable_PoM_Observer:
- #paramGetPoM = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/PartOMagic")
- #PoMObs_status=paramGetPoM.GetBool("EnableObserver")
+ # paramGetPoM = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/PartOMagic")
+ # PoMObs_status=paramGetPoM.GetBool("EnableObserver")
PoMObs_status = False
if Observer.isRunning():
- PoMObs_status=True
- #if PoMObs_status:
+ PoMObs_status = True
+ # if PoMObs_status:
Observer.stop()
- # paramGetPoM.SetBool("EnableObserver",False)
+ # paramGetPoM.SetBool("EnableObserver",False)
sayw("disabling PoM Observer")
-
+
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import")
ImportMode_status = 0
- if hasattr(prefs, 'GetInts'):
- if len(prefs.GetInts()) > 0:
- if prefs.GetInt('ImportMode') != 0:
- ImportMode_status = prefs.GetInt('ImportMode')
- prefs.SetInt('ImportMode', 0)
- sayerr('STEP ImportMode NOT as \'Single document\''+'\n')
+ if hasattr(prefs, "GetInts") and len(prefs.GetInts()) > 0:
+ if prefs.GetInt("ImportMode") != 0:
+ ImportMode_status = prefs.GetInt("ImportMode")
+ prefs.SetInt("ImportMode", 0)
+ sayerr("STEP ImportMode NOT as 'Single document'" + "\n")
##ReadShapeCompoundMode
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- ReadShapeCompoundMode_status=paramGetVS.GetBool("ReadShapeCompoundMode")
- #sayerr("checking ReadShapeCompoundMode")
- sayw("ReadShapeCompoundMode status "+str(ReadShapeCompoundMode_status))
- #FreeCAD.Console.PrintLog("ReadShapeCompoundMode status "+str(ReadShapeCompoundMode_status)+"\n")
- #stop
- enable_ReadShapeCompoundMode=False
- if ReadShapeCompoundMode_status and allow_compound=='True' \
- or ReadShapeCompoundMode_status and allow_compound=='Hierarchy':
+ ReadShapeCompoundMode_status = paramGetVS.GetBool("ReadShapeCompoundMode")
+ # sayerr("checking ReadShapeCompoundMode")
+ sayw("ReadShapeCompoundMode status " + str(ReadShapeCompoundMode_status))
+ # FreeCAD.Console.PrintLog("ReadShapeCompoundMode status "+str(ReadShapeCompoundMode_status)+"\n")
+ # stop
+ enable_ReadShapeCompoundMode = False
+ if (ReadShapeCompoundMode_status and allow_compound == "True") or (
+ ReadShapeCompoundMode_status and allow_compound == "Hierarchy"
+ ):
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- paramGetVS.SetBool("ReadShapeCompoundMode",False)
+ paramGetVS.SetBool("ReadShapeCompoundMode", False)
sayw("disabling ReadShapeCompoundMode")
- enable_ReadShapeCompoundMode=True
- elif not ReadShapeCompoundMode_status and allow_compound=='Simplified':
+ enable_ReadShapeCompoundMode = True
+ elif not ReadShapeCompoundMode_status and allow_compound == "Simplified":
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- paramGetVS.SetBool("ReadShapeCompoundMode",True)
+ paramGetVS.SetBool("ReadShapeCompoundMode", True)
sayw("enabling ReadShapeCompoundMode -> Simplified Mode")
- enable_ReadShapeCompoundMode=True
- #paramGetVS.SetBool("ReadShapeCompoundMode",False)
+ enable_ReadShapeCompoundMode = True
+ # paramGetVS.SetBool("ReadShapeCompoundMode",False)
if load_sketch:
- FreeCADGui.ActiveDocument.getObject(newname).Visibility=False # hidden Sketch
+ FreeCADGui.ActiveDocument.getObject(newname).Visibility = False # hidden Sketch
##Load 3D models
- #Load_models(pcbThickness,modules)
- if (zfit):
+ # Load_models(pcbThickness,modules)
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- #else:
- Load_models(pcbThickness,modules)
-
- #enable_ReadShapeCompoundMode=False
+ # else:
+ Load_models(pcbThickness, modules)
+
+ # enable_ReadShapeCompoundMode=False
if enable_ReadShapeCompoundMode:
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- paramGetVS.SetBool("ReadShapeCompoundMode",ReadShapeCompoundMode_status)
+ paramGetVS.SetBool("ReadShapeCompoundMode", ReadShapeCompoundMode_status)
sayw("enabling ReadShapeCompoundMode")
- if disable_VBO:
- if VBO_status:
- paramGetV.SetBool("UseVBO",True)
- sayw("enabling VBO")
- if disable_PoM_Observer:
- if PoMObs_status:
- Observer.start()
- # paramGetPoM.SetBool("EnableObserver",True)
- sayw("enabling PoM Observer")
-
+ if disable_VBO and VBO_status:
+ paramGetV.SetBool("UseVBO", True)
+ sayw("enabling VBO")
+ if disable_PoM_Observer and PoMObs_status:
+ Observer.start()
+ # paramGetPoM.SetBool("EnableObserver",True)
+ sayw("enabling PoM Observer")
+
def find_nth(haystack, needle, n):
start = haystack.find(needle)
while start >= 0 and n > 1:
- start = haystack.find(needle, start+len(needle))
+ start = haystack.find(needle, start + len(needle))
n -= 1
return start
-
- msg=""
- n_rpt=0
+
+ msg = ""
+ n_rpt = 0
for mod3d in modules:
- #say(mod3d)
- #for e in mod3d:
+ # say(mod3d)
+ # for e in mod3d:
# print e #.decode("utf-8")
- #if mod3d[5] is not None:
+ # if mod3d[5] is not None:
if mod3d[5] != "":
- say(mod3d[0]);sayw(" error: reset"+mod3d[5])
- #stop
- #msg+=""+mod3d[0].decode("utf-8")+" error: "+mod3d[5]+"
"
- msg+=""+mod3d[0]+"
error: "+mod3d[5]+"
"
- n_rpt=n_rpt+1
- n_rpt_max=10
- zf= Timer (0.3,ZoomFitThread)
+ say(mod3d[0])
+ sayw(" error: reset" + mod3d[5])
+ # stop
+ # msg+=""+mod3d[0].decode("utf-8")+" error: "+mod3d[5]+"
"
+ msg += "" + mod3d[0] + "
error: " + mod3d[5] + "
"
+ n_rpt = n_rpt + 1
+ n_rpt_max = 10
+ zf = Timer(0.3, ZoomFitThread)
zf.start()
- if (show_messages==True) and msg!="":
- msg="""error in model(s)
"""+msg
+ if (show_messages) and msg != "":
+ msg = """error in model(s)
""" + msg
QtGui.QApplication.restoreOverrideCursor()
- #print n_rpt,'-',p_rpt
- if n_rpt > n_rpt_max:
- p_rpt=find_nth(msg, '
', n_rpt_max)
- #print n_rpt,'-',p_rpt
- reply = QtGui.QMessageBox.information(None,"Info ...",msg[:p_rpt]+'
. . .')
+ # print n_rpt,'-',p_rpt
+ if n_rpt > n_rpt_max:
+ p_rpt = find_nth(msg, "
", n_rpt_max)
+ # print n_rpt,'-',p_rpt
+ reply = QtGui.QMessageBox.information(None, "Info ...", msg[:p_rpt] + "
. . .")
else:
- reply = QtGui.QMessageBox.information(None,"Info ...",msg)
-
- #if 'LinkView' in dir(FreeCADGui):
+ reply = QtGui.QMessageBox.information(None, "Info ...", msg)
+
+ # if 'LinkView' in dir(FreeCADGui):
# FreeCADGui.Selection.clearSelection()
# o=FreeCAD.ActiveDocument.getObject('Board')
# #FreeCADGui.Selection.addSelection('Board')
@@ -7347,78 +7923,96 @@ def find_nth(haystack, needle, n):
# clps = Timer (3,collaps_Tree)
# clps.start()
if export_board_2step:
- #say('aliveTrue')
+ # say('aliveTrue')
Export2MCAD(blacklisted_model_elements)
else:
- #say('aliveFalse')
+ # say('aliveFalse')
Display_info(blacklisted_model_elements)
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
if restore_specular_cls:
restore_specular(objs_pre)
- msg="running time: "+str(round(running_time,3))+"sec"
+ msg = "running time: " + str(running_time) + "sec"
say(msg)
- zf= Timer (0.3,ZoomFitThread)
+ zf = Timer(0.3, ZoomFitThread)
zf.start()
zf.cancel()
- if SketchLayer != 'Edge.Cuts' and SketchLayer is not None:
+ if SketchLayer != "Edge.Cuts" and SketchLayer is not None:
FreeCADGui.ActiveDocument.ActiveView.viewTop()
- if grid_orig_warn: #adding a warning message because GridOrigin is set in FC Preferences but not set in KiCAD pcbnew file
- msg = 'GridOrigin is set in FC Preferences but not set in KiCAD pcbnew file'
+ if (
+ grid_orig_warn
+ ): # adding a warning message because GridOrigin is set in FC Preferences but not set in KiCAD pcbnew file
+ msg = "GridOrigin is set in FC Preferences but not set in KiCAD pcbnew file"
sayw(msg)
QtGui.QApplication.restoreOverrideCursor()
- msg="""GridOrigin is set in FreeCAD Preferences
but not set in KiCAD pcbnew file"""
- msg+="""
Please assign Grid Origin to your KiCAD pcbnew board file"""
- msg+="""
for a better Mechanical integration"""
- reply = QtGui.QMessageBox.information(None,"Warning ...",msg)
- elif aux_orig_warn: #adding a warning message because AuxOrigin is set in FC Preferences but not set in KiCAD pcbnew file
- msg = 'AuxOrigin is set in FC Preferences but not set in KiCAD pcbnew file'
+ msg = """GridOrigin is set in FreeCAD Preferences
but not set in KiCAD pcbnew file"""
+ msg += """
Please assign Grid Origin to your KiCAD pcbnew board file"""
+ msg += """
for a better Mechanical integration"""
+ reply = QtGui.QMessageBox.information(None, "Warning ...", msg)
+ elif (
+ aux_orig_warn
+ ): # adding a warning message because AuxOrigin is set in FC Preferences but not set in KiCAD pcbnew file
+ msg = "AuxOrigin is set in FC Preferences but not set in KiCAD pcbnew file"
sayw(msg)
QtGui.QApplication.restoreOverrideCursor()
- msg="""AuxOrigin is set in FreeCAD Preferences
but not set in KiCAD pcbnew file"""
- msg+="""
Please assign Aux Origin to your KiCAD pcbnew board file"""
- msg+="""
for a better Mechanical integration"""
- reply = QtGui.QMessageBox.information(None,"Warning ...",msg)
+ msg = """AuxOrigin is set in FreeCAD Preferences
but not set in KiCAD pcbnew file"""
+ msg += """
Please assign Aux Origin to your KiCAD pcbnew board file"""
+ msg += """
for a better Mechanical integration"""
+ reply = QtGui.QMessageBox.information(None, "Warning ...", msg)
prefsKSU = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import")
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- ReadShapeCompoundMode_status=paramGetVS.GetBool("ReadShapeCompoundMode")
+ ReadShapeCompoundMode_status = paramGetVS.GetBool("ReadShapeCompoundMode")
if ImportMode_status != 0:
- prefs.SetInt('ImportMode',ImportMode_status)
- FCV_date = ''
+ prefs.SetInt("ImportMode", ImportMode_status)
+ FCV_date = ""
STEP_UseAppPart_available = False
- if len (FreeCAD.Version()) >= 5:
+ if len(FreeCAD.Version()) >= 5:
FCV_date = str(FreeCAD.Version()[-3])
- FCV_date = FCV_date[0:FCV_date.find(' ')]
- say('FreeCAD version: '+FreeCAD.Version()[0]+'.'+FreeCAD.Version()[1])
- say('FreeCAD build date: '+FCV_date)
- if FCV_date >= '2020/06/27':
- STEP_UseAppPart_available = True #new STEP import export mode available
- say('STEP UseAppPart available')
- if hasattr(prefs, 'GetBools'):
- if (('UseAppPart' in prefs.GetBools() or 'UseLinkGroup' in prefs.GetBools()) and STEP_UseAppPart_available) or len (prefs.GetBools()) == 0:
- if (not prefs.GetBool('UseAppPart') and not ('UseLinkGroup' in prefs.GetBools())) or prefs.GetBool('UseLegacyImporter') or not prefs.GetBool('UseBaseName')\
- or prefs.GetBool('ExportLegacy') or ReadShapeCompoundMode_status or prefs.GetBool('UseLinkGroup'): # or ImportMode_status != 0:
- msg = "Please set your preferences for STEP Import Export as in the displayed image\n"
- msg += "(you can disable this warning on StepUp preferences)\n"
- if 'help_warning_enabled' in prefsKSU.GetBools():
- if prefsKSU.GetBool('help_warning_enabled'):
- StepPrefsDlg = QtGui.QDialog()
- ui = Ui_STEP_Preferences()
- ui.setupUi(StepPrefsDlg)
- reply=StepPrefsDlg.exec_()
- sayw(msg)
- #QtGui.QApplication.restoreOverrideCursor()
- #reply = QtGui.QMessageBox.information(None,"Info ...",msg)
- else: #first time new settings parameter
- StepPrefsDlg = QtGui.QDialog()
- ui = Ui_STEP_Preferences()
- ui.setupUi(StepPrefsDlg)
- reply=StepPrefsDlg.exec_()
- sayw(msg)
+ FCV_date = FCV_date[0 : FCV_date.find(" ")]
+ say("FreeCAD version: " + FreeCAD.Version()[0] + "." + FreeCAD.Version()[1])
+ say("FreeCAD build date: " + FCV_date)
+ if FCV_date >= "2020/06/27":
+ STEP_UseAppPart_available = True # new STEP import export mode available
+ say("STEP UseAppPart available")
+ if (
+ hasattr(prefs, "GetBools")
+ and (
+ (
+ ("UseAppPart" in prefs.GetBools() or "UseLinkGroup" in prefs.GetBools())
+ and STEP_UseAppPart_available
+ )
+ or len(prefs.GetBools()) == 0
+ )
+ and (
+ (not prefs.GetBool("UseAppPart") and "UseLinkGroup" not in prefs.GetBools())
+ or prefs.GetBool("UseLegacyImporter")
+ or not prefs.GetBool("UseBaseName")
+ or prefs.GetBool("ExportLegacy")
+ or ReadShapeCompoundMode_status
+ or prefs.GetBool("UseLinkGroup")
+ )
+ ): # or ImportMode_status != 0:
+ msg = "Please set your preferences for STEP Import Export as in the displayed image\n"
+ msg += "(you can disable this warning on StepUp preferences)\n"
+ if "help_warning_enabled" in prefsKSU.GetBools():
+ if prefsKSU.GetBool("help_warning_enabled"):
+ StepPrefsDlg = QtGui.QDialog()
+ ui = Ui_STEP_Preferences()
+ ui.setupUi(StepPrefsDlg)
+ reply = StepPrefsDlg.exec_()
+ sayw(msg)
+ # QtGui.QApplication.restoreOverrideCursor()
+ # reply = QtGui.QMessageBox.information(None,"Info ...",msg)
+ else: # first time new settings parameter
+ StepPrefsDlg = QtGui.QDialog()
+ ui = Ui_STEP_Preferences()
+ ui.setupUi(StepPrefsDlg)
+ reply = StepPrefsDlg.exec_()
+ sayw(msg)
# TB reviewed
- #if 'LinkView' in dir(FreeCADGui):
+ # if 'LinkView' in dir(FreeCADGui):
# FreeCADGui.Selection.clearSelection()
# o=FreeCAD.ActiveDocument.getObject('Board')
# #FreeCADGui.Selection.addSelection('Board')
@@ -7433,946 +8027,982 @@ def find_nth(haystack, needle, n):
# FreeCADGui.Selection.addSelection(doc.Name,o.Name)
# #collaps_Tree()
# clps.start()
-
- #say_time()
- #stop
+
+ # say_time()
+ # stop
+
def removing_kobjs():
- ''' removing objects after delay '''
+ """removing objects after delay"""
from kicadStepUptools import removesubtree
- doc=FreeCAD.ActiveDocument
+
+ doc = FreeCAD.ActiveDocument
if doc is not None:
- doc.openTransaction('rmv_objs_kicad')
+ doc.openTransaction("rmv_objs_kicad")
for tbr in objs_toberemoved:
removesubtree(tbr)
doc.commitTransaction()
# doc.undo()
# doc.undo()
# adding a timer to allow double transactions during the python code
- QtCore.QTimer.singleShot(0.2,removing_kobjs)
- if (zfit):
+
+ QtCore.QTimer.singleShot(0.2, removing_kobjs)
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- #ImportGui.insert(u"./c0603.step","demo_5D_vrml_from_step")
- if (not pt_lnx): # and (not pt_osx): issue on AppImages hanging on loading
+ # ImportGui.insert(u"./c0603.step","demo_5D_vrml_from_step")
+ if not pt_lnx: # and (not pt_osx): issue on AppImages hanging on loading
FreeCADGui.SendMsgToActiveView("ViewFit")
else:
- zf= Timer (0.25,ZoomFitThread)
+ zf = Timer(0.25, ZoomFitThread)
zf.start()
-
-
+
+
###
-def routineR_XYZ(axe,alpha):
+
+def routineR_XYZ(axe, alpha):
global resetP
- say('routine Rotate XYZ')
- if 0:
- if "Assembly2Workbench" not in FreeCADGui.activeWorkbench().name():
- if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
- FreeCADGui.activateWorkbench("PartWorkbench")
- #FreeCADGui.SendMsgToActiveView("ViewFit")
+ say("routine Rotate XYZ")
+ if False:
+ if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
+ FreeCADGui.activateWorkbench("PartWorkbench")
+ # FreeCADGui.SendMsgToActiveView("ViewFit")
##FreeCADGui.activeDocument().activeView().viewTop()
doc = FreeCAD.ActiveDocument
- #FreeCAD.Console.PrintMessage("hereXYZ !")
+ # FreeCAD.Console.PrintMessage("hereXYZ !")
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
if len(objs) == 1:
- #if len(sel[0]) == 1:
- doc.openTransaction('rot')
+ # if len(sel[0]) == 1:
+ doc.openTransaction("rot")
check_AP()
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
s = objs[0].Shape
- shape=s.copy()
- shape.Placement=s.Placement;
+ shape = s.copy()
+ shape.Placement = s.Placement
boundBox_ = s.BoundBox
boundBoxLX = boundBox_.XLength
boundBoxLY = boundBox_.YLength
boundBoxLZ = boundBox_.ZLength
a = str(boundBox_)
- a,b = a.split('(')
- c = b.split(',')
+ a, b = a.split("(")
+ c = b.split(",")
oripl_X = float(c[0])
oripl_Y = float(c[1])
oripl_Z = float(c[2])
- #say("bbx: "+str(boundBoxLX)+" bby: "+str(boundBoxLY)+"bbz: "+str(boundBoxLZ))
- #say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
- #shape.rotate((oripl_X,oripl_Y,oripl_Z),(1,0,0),90)
- angle=alpha
- if axe=='x':
- #shape.rotate((0,0,0),(1,0,0),90)
- shape.rotate((oripl_X+boundBoxLX/2,oripl_Y+boundBoxLY/2,oripl_Z+boundBoxLZ/2),(1,0,0),int(angle))
- if axe=='y':
- #shape.rotate((0,0,0),(0,1,0),90)
- shape.rotate((oripl_X+boundBoxLX/2,oripl_Y+boundBoxLY/2,oripl_Z+boundBoxLZ/2),(0,1,0),int(angle))
- if axe=='z':
- #shape.rotate((0,0,0),(0,0,1),90)
- shape.rotate((oripl_X+boundBoxLX/2,oripl_Y+boundBoxLY/2,oripl_Z+boundBoxLZ/2),(0,0,1),int(angle))
- #Part.show(shape)
- objs[0].Placement=shape.Placement
+ # say("bbx: "+str(boundBoxLX)+" bby: "+str(boundBoxLY)+"bbz: "+str(boundBoxLZ))
+ # say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
+ # shape.rotate((oripl_X,oripl_Y,oripl_Z),(1,0,0),90)
+ angle = alpha
+ if axe == "x":
+ # shape.rotate((0,0,0),(1,0,0),90)
+ shape.rotate(
+ (oripl_X + boundBoxLX / 2, oripl_Y + boundBoxLY / 2, oripl_Z + boundBoxLZ / 2),
+ (1, 0, 0),
+ int(angle),
+ )
+ if axe == "y":
+ # shape.rotate((0,0,0),(0,1,0),90)
+ shape.rotate(
+ (oripl_X + boundBoxLX / 2, oripl_Y + boundBoxLY / 2, oripl_Z + boundBoxLZ / 2),
+ (0, 1, 0),
+ int(angle),
+ )
+ if axe == "z":
+ # shape.rotate((0,0,0),(0,0,1),90)
+ shape.rotate(
+ (oripl_X + boundBoxLX / 2, oripl_Y + boundBoxLY / 2, oripl_Z + boundBoxLZ / 2),
+ (0, 0, 1),
+ int(angle),
+ )
+ # Part.show(shape)
+ objs[0].Placement = shape.Placement
FreeCADGui.Selection.addSelection(objs[0])
FreeCAD.activeDocument().recompute()
- if resetP==True:
- #doc.commitTransaction()
+ if resetP:
+ # doc.commitTransaction()
routineResetPlacement()
doc.commitTransaction()
- #say("end of rotineZ!")
+ # say("end of rotineZ!")
else:
say(translate("Say", "Select ONE single part object !"))
say_single_obj()
- #QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
+ # QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
+
+
### end RotateXYZ
-def routineT_XYZ(axe,v):
+
+def routineT_XYZ(axe, v):
global resetP
- say('routine Translate XYZ')
- if 0:
- if "Assembly2Workbench" not in FreeCADGui.activeWorkbench().name():
- if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
- FreeCADGui.activateWorkbench("PartWorkbench")
- #FreeCADGui.SendMsgToActiveView("ViewFit")
+ say("routine Translate XYZ")
+ if False:
+ if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
+ FreeCADGui.activateWorkbench("PartWorkbench")
+ # FreeCADGui.SendMsgToActiveView("ViewFit")
##FreeCADGui.activeDocument().activeView().viewTop()
doc = FreeCAD.ActiveDocument
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
if len(objs) == 1:
- doc.openTransaction('trs')
+ doc.openTransaction("trs")
check_AP()
selEx = FreeCADGui.Selection.getSelectionEx()
if 0:
- vis_objs=[]
+ vis_objs = []
for selobj in selEx:
- if selobj.Object.ViewObject.isVisible==True:
+ if selobj.Object.ViewObject.isVisible:
vis_obj.append(selobj.Object)
- objs = [o for o in vis_objs]
+ objs = list(vis_objs)
objs = [selobj.Object for selobj in selEx]
s = objs[0].Shape
- shape=s.copy()
- shape.Placement=s.Placement;
- #shape.rotate((oripl_X,oripl_Y,oripl_Z),(1,0,0),90)
- #say("axe "+axe+", value "+v)
- if axe=='x':
- shape.translate((float(v),0,0))
- if axe=='y':
- shape.translate((0,float(v),0))
- if axe=='z':
- shape.translate((0,0,float(v)))
- #Part.show(shape)
- objs[0].Placement=shape.Placement
+ shape = s.copy()
+ shape.Placement = s.Placement
+ # shape.rotate((oripl_X,oripl_Y,oripl_Z),(1,0,0),90)
+ # say("axe "+axe+", value "+v)
+ if axe == "x":
+ shape.translate((float(v), 0, 0))
+ if axe == "y":
+ shape.translate((0, float(v), 0))
+ if axe == "z":
+ shape.translate((0, 0, float(v)))
+ # Part.show(shape)
+ objs[0].Placement = shape.Placement
FreeCADGui.Selection.addSelection(objs[0])
FreeCAD.activeDocument().recompute()
- if resetP==True:
+ if resetP:
routineResetPlacement()
doc.commitTransaction()
- #say("end of rotineT!")
+ # say("end of rotineT!")
else:
say(translate("Say", "Select ONE single part object !"))
say_single_obj()
- #QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
+ # QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
+
+
### end TranslateXYZ
+
def routineResetPlacement(keepWB=None):
-
- objs=[]
- if 0:
- if "Assembly2Workbench" not in FreeCADGui.activeWorkbench().name():
- if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
- if keepWB is None:
- FreeCADGui.activateWorkbench("PartWorkbench")
- #FreeCADGui.SendMsgToActiveView("ViewFit")
+
+ objs = []
+ if False:
+ if "PartWorkbench" not in FreeCADGui.activeWorkbench().name() and keepWB is None:
+ FreeCADGui.activateWorkbench("PartWorkbench")
+ # FreeCADGui.SendMsgToActiveView("ViewFit")
##FreeCADGui.activeDocument().activeView().viewTop()
- doc = FreeCAD.ActiveDocument
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
- #print 'here'
+ # print 'here'
if len(objs) == 1:
# doc.openTransaction('rst')
- #say('routine reset Placement properties')
+ # say('routine reset Placement properties')
# print(objs[0].Label)
- CpyName = ''; RefName = ''
- if objs[0] != 'App::Part': # using std method
+ CpyName = ""
+ RefName = ""
+ if objs[0] != "App::Part": # using std method
# if objs[0].TypeId == 'Part::MultiFuse' or objs[0].TypeId == 'Part::Compound' or \
# objs[0].TypeId == 'Part::Cut' or objs[0].TypeId == 'Part::MultiCommon': # workaround for issue in resetting pacement for STEP 'merge' importing
if 1:
- say('routine reset Placement std')
- s=objs[0].Shape
- r=[]
- t=s.copy()
+ say("routine reset Placement std")
+ s = objs[0].Shape
+ r = []
+ t = s.copy()
for i in t.childShapes():
- c=i.copy()
- c.Placement=t.Placement.multiply(c.Placement)
- r.append((i,c))
- w=t.replaceShape(r)
- w.Placement=FreeCAD.Placement()
+ c = i.copy()
+ c.Placement = t.Placement.multiply(c.Placement)
+ r.append((i, c))
+ w = t.replaceShape(r)
+ w.Placement = FreeCAD.Placement()
Part.show(w)
CpyName = FreeCAD.ActiveDocument.ActiveObject.Name
- #say(w)
+ # say(w)
## removed the need to workaround, with FC fix
else: # workaround for issue in resetting pacement for STEP 'merge' importing
- say('routine reset Placement refining')
- FreeCAD.ActiveDocument.addObject('Part::Refine','Refined').Source=FreeCAD.ActiveDocument.getObject(objs[0].Name)
+ say("routine reset Placement refining")
+ FreeCAD.ActiveDocument.addObject("Part::Refine", "Refined").Source = FreeCAD.ActiveDocument.getObject(
+ objs[0].Name,
+ )
RefName = FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.recompute()
- __shape = Part.getShape(FreeCAD.ActiveDocument.getObject(RefName),'',needSubElement=False,refine=False)
- FreeCAD.ActiveDocument.addObject('Part::Feature','sc').Shape=__shape
- #FreeCAD.ActiveDocument.recompute()
+ __shape = Part.getShape(
+ FreeCAD.ActiveDocument.getObject(RefName),
+ "",
+ needSubElement=False,
+ refine=False,
+ )
+ FreeCAD.ActiveDocument.addObject("Part::Feature", "sc").Shape = __shape
+ # FreeCAD.ActiveDocument.recompute()
CpyName = FreeCAD.ActiveDocument.ActiveObject.Name
# FreeCAD.ActiveDocument.ActiveObject.Label=FreeCAD.ActiveDocument.getObject('Part__Feature001').Label
- if hasattr(FreeCADGui.ActiveDocument.getObject(objs[0].Name),'ShapeColor'):
- say('has shapecolor')
- FreeCADGui.ActiveDocument.getObject(CpyName).ShapeColor=FreeCADGui.ActiveDocument.getObject(objs[0].Name).ShapeColor
- FreeCADGui.ActiveDocument.getObject(CpyName).LineColor=FreeCADGui.ActiveDocument.getObject(objs[0].Name).LineColor
- FreeCADGui.ActiveDocument.getObject(CpyName).PointColor=FreeCADGui.ActiveDocument.getObject(objs[0].Name).PointColor
- FreeCADGui.ActiveDocument.getObject(CpyName).DiffuseColor=FreeCADGui.ActiveDocument.getObject(objs[0].Name).DiffuseColor
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(objs[0].Name).Transparency
-
- new_label=objs[0].Label
- if RefName != '':
+ if hasattr(FreeCADGui.ActiveDocument.getObject(objs[0].Name), "ShapeColor"):
+ say("has shapecolor")
+ FreeCADGui.ActiveDocument.getObject(CpyName).ShapeColor = FreeCADGui.ActiveDocument.getObject(
+ objs[0].Name,
+ ).ShapeColor
+ FreeCADGui.ActiveDocument.getObject(CpyName).LineColor = FreeCADGui.ActiveDocument.getObject(
+ objs[0].Name,
+ ).LineColor
+ FreeCADGui.ActiveDocument.getObject(CpyName).PointColor = FreeCADGui.ActiveDocument.getObject(
+ objs[0].Name,
+ ).PointColor
+ FreeCADGui.ActiveDocument.getObject(CpyName).DiffuseColor = FreeCADGui.ActiveDocument.getObject(
+ objs[0].Name,
+ ).DiffuseColor
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject(
+ objs[0].Name,
+ ).Transparency
+
+ new_label = objs[0].Label
+ if RefName != "":
FreeCAD.ActiveDocument.removeObject(RefName)
- if objs[0].TypeId == 'PartDesign::Body' or 'PartDesign::' in objs[0].TypeId or len(objs[0].OutList)>0:
- FreeCAD.ActiveDocument.getObject(objs[0].Name).ViewObject.Visibility=False
+ if objs[0].TypeId == "PartDesign::Body" or "PartDesign::" in objs[0].TypeId or len(objs[0].OutList) > 0:
+ FreeCAD.ActiveDocument.getObject(objs[0].Name).ViewObject.Visibility = False
else:
FreeCAD.ActiveDocument.removeObject(objs[0].Name)
FreeCAD.ActiveDocument.recompute()
- FreeCAD.ActiveDocument.ActiveObject.Label=new_label
- rObj=FreeCAD.ActiveDocument.getObject(CpyName)
+ FreeCAD.ActiveDocument.ActiveObject.Label = new_label
+ FreeCAD.ActiveDocument.getObject(CpyName)
del objs
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(CpyName))
- #doc.commitTransaction()
- #FreeCAD.activeDocument().recompute()
- #say("end of rotineRP!")
+ # doc.commitTransaction()
+ # FreeCAD.activeDocument().recompute()
+ # say("end of rotineRP!")
else:
say(translate("Say", "Select ONE single part object !"))
say_single_obj()
- #QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
+ # QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
del objs
+
+
### end reset prop
+
def routineScaleVRML():
global exportV, exportS, applymaterials
if FreeCAD.ActiveDocument.FileName == "":
msg = translate("Save", "please save your job file before exporting.")
QtGui.QApplication.restoreOverrideCursor()
- QtGui.QMessageBox.information(None,translate("Save", "Info ..."),msg)
+ QtGui.QMessageBox.information(None, translate("Save", "Info ..."), msg)
FreeCADGui.SendMsgToActiveView(translate("Save", "Save"))
- say(translate("Say", 'routine Scale to VRML 1/2.54'))
+ say(translate("Say", "routine Scale to VRML 1/2.54"))
cfg_read_all()
doc = FreeCAD.ActiveDocument
- doc.openTransaction('exportModel')
+ doc.openTransaction("exportModel")
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
- if len(objs) >= 1: #allow more than 1 obj for vrml
- say('exporting')
- fullFilePathName=doc.FileName
- if fullFilePathName=="":
+ if len(objs) >= 1: # allow more than 1 obj for vrml
+ say("exporting")
+ fullFilePathName = doc.FileName
+ if fullFilePathName == "":
if os.path.exists(models3D_prefix):
if isWritable(models3D_prefix):
- #if os.access(models3D_prefix, os.W_OK | os.X_OK):
+ # if os.access(models3D_prefix, os.W_OK | os.X_OK):
models3D_prefix_tosave = re.sub("\\\\", "/", models3D_prefix)
- if models3D_prefix_tosave.endswith('/'):
- fullFilePathName=models3D_prefix+doc.Label+'.FCStd'
+ if models3D_prefix_tosave.endswith("/"):
+ fullFilePathName = models3D_prefix + doc.Label + ".FCStd"
else:
- fullFilePathName=models3D_prefix+os.sep+doc.Label+'.FCStd'
- say('saving to '+models3D_prefix_tosave)
+ fullFilePathName = models3D_prefix + os.sep + doc.Label + ".FCStd"
+ say("saving to " + models3D_prefix_tosave)
else:
home = expanduser("~")
- fullFilePathName=home+os.sep+doc.Label+'.FCStd'
- say('path not found/writable, saving to '+home)
- #say(fullFilePathName)
+ fullFilePathName = home + os.sep + doc.Label + ".FCStd"
+ say("path not found/writable, saving to " + home)
+ # say(fullFilePathName)
else:
- home = expanduser("~")
- fullFilePathName=home+os.sep+doc.Label+'.FCStd'
- say('path not found/writable, saving to '+home)
- #say(fullFilePathName)
+ home = expanduser("~")
+ fullFilePathName = home + os.sep + doc.Label + ".FCStd"
+ say("path not found/writable, saving to " + home)
+ # say(fullFilePathName)
else:
say(fullFilePathName)
- lbl=go_export(fullFilePathName)
+ lbl = go_export(fullFilePathName)
path, fname = os.path.split(fullFilePathName)
- #fname=os.path.splitext(fname)[0]
- #fname=objs[0].Label
+ # fname=os.path.splitext(fname)[0]
+ # fname=objs[0].Label
##fname=FreeCAD.ActiveDocument.ActiveObject.Label #step reset placement
- fname=lbl #step reset placement
- #removing not allowed chars
- translation_table = dict.fromkeys(map(ord, '<>:"/\|?*,;:\\'), None)
- fname=fname.translate(translation_table)
- vrml_ext='.wrl'
+ fname = lbl # step reset placement
+ # removing not allowed chars
+ translation_table = dict.fromkeys(map(ord, '<>:"/\\|?*,;:\\'), None)
+ fname = fname.translate(translation_table)
+ vrml_ext = ".wrl"
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if prefs.GetBool('wrz_export_enabled'):
+ if prefs.GetBool("wrz_export_enabled"):
#'stpz'
- vrml_ext='.wrz'
- stp_ext='.step'
- if prefs.GetBool('stpz_export_enabled'):
- stp_ext='.stpZ'
- #print('stpZ',fullFilePathNameStep)
+ vrml_ext = ".wrz"
+ stp_ext = ".step"
+ if prefs.GetBool("stpz_export_enabled"):
+ stp_ext = ".stpZ"
+ # print('stpZ',fullFilePathNameStep)
if exportV or exportS:
- msg="""export STEP & scaled VRML file for kicad!
+ msg = (
+ """export STEP & scaled VRML file for kicad!
****************************************************************************
- exporting folder:
- """+path+""""""
- msg+="""
exporting filename:
"""
+ exporting folder:
- """
+ + path
+ + """"""
+ )
+ msg += """
exporting filename:
"""
if exportV:
- msg+="""- """+fname+vrml_ext+"""
"""
+ msg += """- """ + fname + vrml_ext + """
"""
if exportS:
- msg+="""- """+fname+stp_ext+""""""
- else:
- if len(objs) >= 1:
- msg+="""
- step file not exported; multi-part selected"""
- #msg="export scaled VRML file for kicad!\r\n"
- #msg=msg+"****************************************************************************"
- msg=msg+"
3D settings in kicad Module Editor:
"
- msg=msg+"- scale 1 1 1\r\n- offset 0 0 0
- rotation 0 0 "+str(rot_wrl)+""
+ msg += """- """ + fname + stp_ext + """"""
+ elif len(objs) >= 1:
+ msg += """
- step file not exported; multi-part selected"""
+ # msg="export scaled VRML file for kicad!\r\n"
+ # msg=msg+"****************************************************************************"
+ msg = msg + "
3D settings in kicad Module Editor:
"
+ msg = msg + "- scale 1 1 1\r\n- offset 0 0 0
- rotation 0 0 " + str(rot_wrl) + ""
##self.setWindowState(QtCore.Qt.WindowMinimized)
QtGui.QApplication.restoreOverrideCursor()
- QtGui.QMessageBox.information(None,"Info ...",msg)
+ QtGui.QMessageBox.information(None, "Info ...", msg)
##self.setWindowState(QtCore.Qt.WindowActive)
- say('done')
+ say("done")
FreeCAD.ActiveDocument.commitTransaction()
else:
say(translate("Say", "Select ONE single part object !"))
say_single_obj()
- #QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
- return 0
+ # QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
+ return 0
+
+
###
+
###
def routineScaleVRML_1():
global rot_wrl, zfit
- say('routine Scale to VRML 1/2.54')
- if 0:
- if "Assembly2Workbench" not in FreeCADGui.activeWorkbench().name():
- if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
- FreeCADGui.activateWorkbench("PartWorkbench")
- #FreeCADGui.SendMsgToActiveView("ViewFit")
+ say("routine Scale to VRML 1/2.54")
+ if False:
+ if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
+ FreeCADGui.activateWorkbench("PartWorkbench")
+ # FreeCADGui.SendMsgToActiveView("ViewFit")
##FreeCADGui.activeDocument().activeView().viewTop()
- doc = FreeCAD.ActiveDocument
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
if len(objs) == 1:
- objS=FreeCAD.ActiveDocument.getObject(objs[0].Name).Shape
- #FreeCADGui.ActiveDocument.getObject(objs[0].Name).BoundingBox = True
- final_Label=FreeCAD.ActiveDocument.getObject(objs[0].Name).Label
- myobjG=FreeCADGui.ActiveDocument.getObject(objs[0].Name)
- myobjA=FreeCAD.ActiveDocument.getObject(objs[0].Name)
- mynewdoc=FreeCAD.newDocument()
- FreeCAD.ActiveDocument.addObject('Part::Feature',objs[0].Name).Shape=objS
-
- #print 'here'
- myobjA1=FreeCAD.ActiveDocument.ActiveObject
- #myobjA1.Label=final_Label
- myobjG1=FreeCADGui.ActiveDocument.ActiveObject
- myobjG1.ShapeColor=myobjG.ShapeColor
- myobjG1.LineColor=myobjG.LineColor
- myobjG1.PointColor=myobjG.PointColor
- myobjG1.DiffuseColor=myobjG.DiffuseColor
- myobjG1.Transparency=myobjG.Transparency
+ objS = FreeCAD.ActiveDocument.getObject(objs[0].Name).Shape
+ # FreeCADGui.ActiveDocument.getObject(objs[0].Name).BoundingBox = True
+ final_Label = FreeCAD.ActiveDocument.getObject(objs[0].Name).Label
+ myobjG = FreeCADGui.ActiveDocument.getObject(objs[0].Name)
+ FreeCAD.ActiveDocument.getObject(objs[0].Name)
+ FreeCAD.newDocument()
+ FreeCAD.ActiveDocument.addObject("Part::Feature", objs[0].Name).Shape = objS
+
+ # print 'here'
+ # myobjA1.Label=final_Label
+ myobjG1 = FreeCADGui.ActiveDocument.ActiveObject
+ myobjG1.ShapeColor = myobjG.ShapeColor
+ myobjG1.LineColor = myobjG.LineColor
+ myobjG1.PointColor = myobjG.PointColor
+ myobjG1.DiffuseColor = myobjG.DiffuseColor
+ myobjG1.Transparency = myobjG.Transparency
FreeCAD.ActiveDocument.recompute()
- FreeCAD.ActiveDocument.ActiveObject.Label=final_Label+'_vrml'
- say( final_Label+'_vrml' )
- #FreeCADGui.ActiveDocument.getObject(objs[0].Name).Visibility=False
+ FreeCAD.ActiveDocument.ActiveObject.Label = final_Label + "_vrml"
+ say(final_Label + "_vrml")
+ # FreeCADGui.ActiveDocument.getObject(objs[0].Name).Visibility=False
FreeCAD.ActiveDocument.recompute()
- vrml_obj = Draft.scale(FreeCAD.ActiveDocument.ActiveObject,delta=FreeCAD.Vector(0.3937,0.3937,0.3937),center=FreeCAD.Vector(0,0,0),legacy=True)
+ Draft.scale(
+ FreeCAD.ActiveDocument.ActiveObject,
+ delta=FreeCAD.Vector(0.3937, 0.3937, 0.3937),
+ center=FreeCAD.Vector(0, 0, 0),
+ legacy=True,
+ )
FreeCAD.ActiveDocument.recompute()
- #FreeCAD.ActiveDocument.ActiveObject.ViewObject.DisplayMode = 'Shaded'
+ # FreeCAD.ActiveDocument.ActiveObject.ViewObject.DisplayMode = 'Shaded'
FreeCADGui.ActiveDocument.ActiveObject.BoundingBox = False
- #FreeCAD.ActiveDocument.ActiveObject.ViewObject.DisplayMode = 'Shaded'
- #vrml_obj.ViewObject.DisplayMode = u'Shaded'
- shade_val='Shaded'
- #FreeCAD.ActiveDocument.ActiveObject.ViewObject.DisplayMode = 'Shaded'
- FreeCAD.ActiveDocument.ActiveObject.ViewObject.DisplayMode = 1 #Shaded
- if (zfit):
+ # FreeCAD.ActiveDocument.ActiveObject.ViewObject.DisplayMode = 'Shaded'
+ # vrml_obj.ViewObject.DisplayMode = u'Shaded'
+ # FreeCAD.ActiveDocument.ActiveObject.ViewObject.DisplayMode = 'Shaded'
+ FreeCAD.ActiveDocument.ActiveObject.ViewObject.DisplayMode = 1 # Shaded
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- msg="""export scaled VRML file for kicad!
+ msg = f"""export scaled VRML file for kicad!
****************************************************************************
3D settings in kicad Module Editor:
- - scale 1 1 1\r\n- offset 0 0 0\r\n- rotation 0 0 {0}
- """.format(rot_wrl)
- #msg="export scaled VRML file for kicad!\r\n"
- #msg=msg+"****************************************************************************"
- #msg=msg+"\r\n3D settings in kicad Module Editor:\r\n"
- #msg=msg+"- scale 1 1 1\r\n- offset 0 0 0\r\n- rotation 0 0 "+str(rot_wrl)
+ - scale 1 1 1\r\n- offset 0 0 0\r\n- rotation 0 0 {rot_wrl}
+ """
+ # msg="export scaled VRML file for kicad!\r\n"
+ # msg=msg+"****************************************************************************"
+ # msg=msg+"\r\n3D settings in kicad Module Editor:\r\n"
+ # msg=msg+"- scale 1 1 1\r\n- offset 0 0 0\r\n- rotation 0 0 "+str(rot_wrl)
self.setWindowState(QtCore.Qt.WindowMinimized)
QtGui.QApplication.restoreOverrideCursor()
- QtGui.QMessageBox.information(None,"Info ...",msg)
+ QtGui.QMessageBox.information(None, "Info ...", msg)
self.setWindowState(QtCore.Qt.WindowActive)
else:
say(translate("Say", "Select ONE single part object !"))
say_single_obj()
- #QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
+ # QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
return 0
+
### end ScaleVRML_1
def routineC_XYZ(axe):
global resetP
- say('routine center position')
- #if self.checkBox_1.isChecked():
+ say("routine center position")
+ # if self.checkBox_1.isChecked():
# routineResetPlacement()
- if 0:
- if "Assembly2Workbench" not in FreeCADGui.activeWorkbench().name():
- if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
- FreeCADGui.activateWorkbench("PartWorkbench")
- #FreeCADGui.SendMsgToActiveView("ViewFit")
+ if False:
+ if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
+ FreeCADGui.activateWorkbench("PartWorkbench")
+ # FreeCADGui.SendMsgToActiveView("ViewFit")
##FreeCADGui.activeDocument().activeView().viewTop()
doc = FreeCAD.ActiveDocument
say("Centering on Axe XYZ !")
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
if len(objs) == 1:
- doc.openTransaction('cntr')
+ doc.openTransaction("cntr")
check_AP()
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
s = objs[0].Shape
- shape=s.copy()
- #shape.Placement=s.Placement;
- shape.Placement= FreeCAD.Placement(FreeCAD.Vector(0,0,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
+ shape = s.copy()
+ # shape.Placement=s.Placement;
+ shape.Placement = FreeCAD.Placement(FreeCAD.Vector(0, 0, 0), FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0))
boundBox_ = s.BoundBox
boundBoxLX = boundBox_.XLength
boundBoxLY = boundBox_.YLength
boundBoxLZ = boundBox_.ZLength
- say("bbox: "+str(boundBox_))
+ say("bbox: " + str(boundBox_))
a = str(boundBox_)
- a,b = a.split('(')
- c = b.split(',')
+ a, b = a.split("(")
+ c = b.split(",")
oripl_X = float(c[0])
oripl_Y = float(c[1])
oripl_Z = float(c[2])
- #say("bbx: "+str(boundBoxLX)+" bby: "+str(boundBoxLY)+"bbz: "+str(boundBoxLZ))
- #say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
-
- p=s.Placement
- #say("PlacementBase : "+str(p))
- #say(str(p.Base[0])+' '+str(p.Base[1])+' '+str(p.Base[2]))
- if axe=='x':
- #shape.translate((0,0,0))
- diffPl=-oripl_X-boundBoxLX/2
- #shape.Placement.move(diffPl,0,0)
- #shape.translate(Base.Vector(diffPl,0,0))
- shape.translate((diffPl,p.Base[1],p.Base[2]))
- if axe=='y':
- diffPl=-oripl_Y-boundBoxLY/2
- #shape.translate(Base.Vector(0,diffPl,0))
- shape.translate((p.Base[0],diffPl,p.Base[2]))
- if axe=='z':
- diffPl=-oripl_Z-boundBoxLZ/2
- shape.translate((p.Base[0],p.Base[1],diffPl))
- #shape.translate(Base.Vector(0,0,diffPl))
+ # say("bbx: "+str(boundBoxLX)+" bby: "+str(boundBoxLY)+"bbz: "+str(boundBoxLZ))
+ # say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
+
+ p = s.Placement
+ # say("PlacementBase : "+str(p))
+ # say(str(p.Base[0])+' '+str(p.Base[1])+' '+str(p.Base[2]))
+ if axe == "x":
+ # shape.translate((0,0,0))
+ diffPl = -oripl_X - boundBoxLX / 2
+ # shape.Placement.move(diffPl,0,0)
+ # shape.translate(Base.Vector(diffPl,0,0))
+ shape.translate((diffPl, p.Base[1], p.Base[2]))
+ if axe == "y":
+ diffPl = -oripl_Y - boundBoxLY / 2
+ # shape.translate(Base.Vector(0,diffPl,0))
+ shape.translate((p.Base[0], diffPl, p.Base[2]))
+ if axe == "z":
+ diffPl = -oripl_Z - boundBoxLZ / 2
+ shape.translate((p.Base[0], p.Base[1], diffPl))
+ # shape.translate(Base.Vector(0,0,diffPl))
### to zero posX -bboxX/2
- #say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
- #say("axe "+axe+" placement"+str(diffPl))
- #Part.show(shape)
- objs[0].Placement=shape.Placement
+ # say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
+ # say("axe "+axe+" placement"+str(diffPl))
+ # Part.show(shape)
+ objs[0].Placement = shape.Placement
FreeCADGui.Selection.addSelection(objs[0])
FreeCAD.activeDocument().recompute()
- #say("x: "+str(oripl_X)+"\r\ny: "+str(oripl_Y)+"\r\nz: "+str(oripl_Z))
- if resetP==True:
+ # say("x: "+str(oripl_X)+"\r\ny: "+str(oripl_Y)+"\r\nz: "+str(oripl_Z))
+ if resetP:
routineResetPlacement()
- #say("pos reset done")
+ # say("pos reset done")
doc.commitTransaction()
- #say("done")
+ # say("done")
else:
say("Select an object !")
say_single_obj()
- #QtGui.QMessageBox.information(None,"Info ...","Select an object !")
+ # QtGui.QMessageBox.information(None,"Info ...","Select an object !")
+
+
### end routineC_XYZ
+
def routineP_XYZ(axe):
global resetP
- say('routine put on axe')
- #routineResetPlacement()
- if 0:
- if "Assembly2Workbench" not in FreeCADGui.activeWorkbench().name():
- if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
- FreeCADGui.activateWorkbench("PartWorkbench")
- #FreeCADGui.SendMsgToActiveView("ViewFit")
+ say("routine put on axe")
+ # routineResetPlacement()
+ if False:
+ if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
+ FreeCADGui.activateWorkbench("PartWorkbench")
+ # FreeCADGui.SendMsgToActiveView("ViewFit")
##FreeCADGui.activeDocument().activeView().viewTop()
doc = FreeCAD.ActiveDocument
say(translate("Say", "Put on Axe XYZ !"))
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
if len(objs) == 1:
- doc.openTransaction('plc')
+ doc.openTransaction("plc")
check_AP()
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
s = objs[0].Shape
- shape=s.copy()
- #shape.Placement=s.Placement;
- shape.Placement= FreeCAD.Placement(FreeCAD.Vector(0,0,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
+ shape = s.copy()
+ # shape.Placement=s.Placement;
+ shape.Placement = FreeCAD.Placement(FreeCAD.Vector(0, 0, 0), FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0))
boundBox_ = s.BoundBox
- boundBoxLX = boundBox_.XLength
- boundBoxLY = boundBox_.YLength
- boundBoxLZ = boundBox_.ZLength
a = str(boundBox_)
- a,b = a.split('(')
- c = b.split(',')
+ a, b = a.split("(")
+ c = b.split(",")
oripl_X = float(c[0])
oripl_Y = float(c[1])
oripl_Z = float(c[2])
- p=s.Placement
- say("PlacementBase : "+str(p))
- #say(str(p.Base[0])+' '+str(p.Base[1])+' '+str(p.Base[2]))
- if axe=='x':
- #shape.translate((0,0,0))
- diffPl=p.Base[0]-oripl_X
- #shape.Placement.move(diffPl,0,0)
- #shape.translate(Base.Vector(diffPl,0,0))
- shape.translate((diffPl,p.Base[1],p.Base[2]))
- if axe=='y':
- diffPl=p.Base[1]-oripl_Y
- #shape.translate(Base.Vector(0,diffPl,0))
- shape.translate((p.Base[0],diffPl,p.Base[2]))
- if axe=='z':
- diffPl=p.Base[2]-oripl_Z
- shape.translate((p.Base[0],p.Base[1],diffPl))
- #shape.translate(Base.Vector(0,0,diffPl))
+ p = s.Placement
+ say("PlacementBase : " + str(p))
+ # say(str(p.Base[0])+' '+str(p.Base[1])+' '+str(p.Base[2]))
+ if axe == "x":
+ # shape.translate((0,0,0))
+ diffPl = p.Base[0] - oripl_X
+ # shape.Placement.move(diffPl,0,0)
+ # shape.translate(Base.Vector(diffPl,0,0))
+ shape.translate((diffPl, p.Base[1], p.Base[2]))
+ if axe == "y":
+ diffPl = p.Base[1] - oripl_Y
+ # shape.translate(Base.Vector(0,diffPl,0))
+ shape.translate((p.Base[0], diffPl, p.Base[2]))
+ if axe == "z":
+ diffPl = p.Base[2] - oripl_Z
+ shape.translate((p.Base[0], p.Base[1], diffPl))
+ # shape.translate(Base.Vector(0,0,diffPl))
### to zero posX -bboxX/2
- #say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
- #say("axe "+axe+" placement"+str(diffPl))
- #Part.show(shape)
- objs[0].Placement=shape.Placement
+ # say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
+ # say("axe "+axe+" placement"+str(diffPl))
+ # Part.show(shape)
+ objs[0].Placement = shape.Placement
FreeCADGui.Selection.addSelection(objs[0])
FreeCAD.activeDocument().recompute()
- #say("x: "+str(oripl_X)+"\r\ny: "+str(oripl_Y)+"\r\nz: "+str(oripl_Z))
- #say("placement "+str(p[0]))
- #return [oripl_X, oripl_Y, oripl_Z,p.Base[0],p.Base[1],p.Base[2]];
- if resetP==True:
+ # say("x: "+str(oripl_X)+"\r\ny: "+str(oripl_Y)+"\r\nz: "+str(oripl_Z))
+ # say("placement "+str(p[0]))
+ # return [oripl_X, oripl_Y, oripl_Z,p.Base[0],p.Base[1],p.Base[2]];
+ if resetP:
routineResetPlacement()
doc.commitTransaction()
else:
say(translate("Say", "Select ONE single part object !"))
say_single_obj()
- #QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n")
+ # QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n")
+
+
### end routineP_XYZ
+
def say_single_obj():
- QtGui.QApplication.restoreOverrideCursor()
- msg = translate("Say", "Select ONE single part object !
\n"
- "suggestion for multi-part:
\n"
- " Part Boolean Union (recommended)
\n"
- "or
\n"
- " Part Make compound (alternative choice)"
- )
- spc="""*******************************************************************************
- """
- msg1=translate("Say", "Error in selection")
- QtGui.QApplication.restoreOverrideCursor()
- #RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical,
- msg1,
- msg)
- diag.setWindowModality(QtCore.Qt.ApplicationModal)
- diag.exec_()
+ QtGui.QApplication.restoreOverrideCursor()
+ msg = translate(
+ "Say",
+ "Select ONE single part object !
\n"
+ "suggestion for multi-part:
\n"
+ " Part Boolean Union (recommended)
\n"
+ "or
\n"
+ " Part Make compound (alternative choice)",
+ )
+ msg1 = translate("Say", "Error in selection")
+ QtGui.QApplication.restoreOverrideCursor()
+ # RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
+ diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical, msg1, msg)
+ diag.setWindowModality(QtCore.Qt.ApplicationModal)
+ diag.exec_()
+
def say_select_obj():
- QtGui.QApplication.restoreOverrideCursor()
- msg = translate("Say",
- "Select a Compound or
\n"
- "a Part Design group
\n"
- "or more than one Part object !
"
- )
- spc="""*******************************************************************************
- """
- msg1=translate("Say", "Error in selection")
- QtGui.QApplication.restoreOverrideCursor()
- #RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical,
- msg1,
- msg)
- diag.setWindowModality(QtCore.Qt.ApplicationModal)
- diag.exec_()
+ QtGui.QApplication.restoreOverrideCursor()
+ msg = translate(
+ "Say",
+ "Select a Compound or
\na Part Design group
\nor more than one Part object !
",
+ )
+ msg1 = translate("Say", "Error in selection")
+ QtGui.QApplication.restoreOverrideCursor()
+ # RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
+ diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical, msg1, msg)
+ diag.setWindowModality(QtCore.Qt.ApplicationModal)
+ diag.exec_()
+
def say_warning(msg):
- QtGui.QApplication.restoreOverrideCursor()
- # msg="""Select a Compound or
a Part Design group
or more than one Part object !
"""
- spc="""*******************************************************************************
- """
- msg1 = translate("Say", "Warning ...")
- QtGui.QApplication.restoreOverrideCursor()
- #RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning,
- msg1,
- msg)
- diag.setWindowModality(QtCore.Qt.ApplicationModal)
- diag.exec_()
+ QtGui.QApplication.restoreOverrideCursor()
+ # msg="""Select a Compound or
a Part Design group
or more than one Part object !
"""
+ msg1 = translate("Say", "Warning ...")
+ QtGui.QApplication.restoreOverrideCursor()
+ # RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
+ diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Warning, msg1, msg)
+ diag.setWindowModality(QtCore.Qt.ApplicationModal)
+ diag.exec_()
+
def say_error(msg):
- QtGui.QApplication.restoreOverrideCursor()
- # msg="""Select a Compound or
a Part Design group
or more than one Part object !
"""
- spc="""*******************************************************************************
- """
- msg1 = translate("Say", "ERROR! ...")
- QtGui.QApplication.restoreOverrideCursor()
- #RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical,
- msg1,
- msg)
- diag.setWindowModality(QtCore.Qt.ApplicationModal)
- diag.exec_()
+ QtGui.QApplication.restoreOverrideCursor()
+ # msg="""Select a Compound or
a Part Design group
or more than one Part object !
"""
+ msg1 = translate("Say", "ERROR! ...")
+ QtGui.QApplication.restoreOverrideCursor()
+ # RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
+ diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical, msg1, msg)
+ diag.setWindowModality(QtCore.Qt.ApplicationModal)
+ diag.exec_()
+
def say_info(msg):
- QtGui.QApplication.restoreOverrideCursor()
- # msg="""Select a Compound or
a Part Design group
or more than one Part object !
"""
- spc="""*******************************************************************************
- """
- msg1 = translate("Say","Info ...")
- QtGui.QApplication.restoreOverrideCursor()
- #RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Information,
- msg1,
- msg)
- diag.setWindowModality(QtCore.Qt.ApplicationModal)
- diag.exec_()
+ QtGui.QApplication.restoreOverrideCursor()
+ # msg="""Select a Compound or
a Part Design group
or more than one Part object !
"""
+ msg1 = translate("Say", "Info ...")
+ QtGui.QApplication.restoreOverrideCursor()
+ # RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
+ diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Information, msg1, msg)
+ diag.setWindowModality(QtCore.Qt.ApplicationModal)
+ diag.exec_()
+
def get_position():
global min_val, exportS
- say('routine get base position')
- if 0:
- if "Assembly2Workbench" not in FreeCADGui.activeWorkbench().name():
- if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
- FreeCADGui.activateWorkbench("PartWorkbench")
- #FreeCADGui.SendMsgToActiveView("ViewFit")
+ say("routine get base position")
+ if False:
+ if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
+ FreeCADGui.activateWorkbench("PartWorkbench")
+ # FreeCADGui.SendMsgToActiveView("ViewFit")
##FreeCADGui.activeDocument().activeView().viewTop()
- doc = FreeCAD.ActiveDocument
- #say("hereXYZ !")
+ # say("hereXYZ !")
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
if len(objs) == 1:
try:
s = objs[0].Shape
boundBox_ = s.BoundBox
- boundBoxLX = boundBox_.XLength
- boundBoxLY = boundBox_.YLength
- boundBoxLZ = boundBox_.ZLength
a = str(boundBox_)
- a,b = a.split('(')
- c = b.split(',')
+ a, b = a.split("(")
+ c = b.split(",")
oripl_X = float(c[0])
oripl_Y = float(c[1])
oripl_Z = float(c[2])
FreeCADGui.Selection.addSelection(objs[0])
FreeCAD.activeDocument().recompute()
- #say("x: "+str(oripl_X)+"\r\ny: "+str(oripl_Y)+"\r\nz: "+str(oripl_Z))
- p=s.Placement
- #say("PlacementBase : "+str(p))
- #say(str(p.Base[0])+' '+str(p.Base[1])+' '+str(p.Base[2]))
+ # say("x: "+str(oripl_X)+"\r\ny: "+str(oripl_Y)+"\r\nz: "+str(oripl_Z))
+ p = s.Placement
+ # say("PlacementBase : "+str(p))
+ # say(str(p.Base[0])+' '+str(p.Base[1])+' '+str(p.Base[2]))
### to zero posX -bboxX/2
- #say("placement "+str(p[0]))
- #min_val=10e-16
- #say("min_val "+str(min_val))
+ # say("placement "+str(p[0]))
+ # min_val=10e-16
+ # say("min_val "+str(min_val))
if abs(oripl_X) < min_val:
- oripl_X=0
+ oripl_X = 0
if abs(oripl_Y) < min_val:
- oripl_Y=0
+ oripl_Y = 0
if abs(oripl_Z) < min_val:
- oripl_Z=0
- return [oripl_X, oripl_Y, oripl_Z,p.Base[0],p.Base[1],p.Base[2]];
+ oripl_Z = 0
+ return [oripl_X, oripl_Y, oripl_Z, p.Base[0], p.Base[1], p.Base[2]]
except:
pass
- else:
- if exportS:
- say(translate("Say", "Select ONE single part object !"))
- ##QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
- #QtGui.QApplication.restoreOverrideCursor()
- #msg="""Select ONE single part object !
- #suggestion for multi-part:
Part Boolean Union (recommended)
or
Part Make compound (alternative choice)"""
- #spc="""*******************************************************************************
- #"""
- #msg1="Error in selection"
- #QtGui.QApplication.restoreOverrideCursor()
- ##RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
- #diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical,
- # msg1,
- # msg)
- #diag.setWindowModality(QtCore.Qt.ApplicationModal)
- #diag.exec_()
+ elif exportS:
+ say(translate("Say", "Select ONE single part object !"))
+ return None
+ ##QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
+ # QtGui.QApplication.restoreOverrideCursor()
+ # msg="""Select ONE single part object !
+ # suggestion for multi-part:
Part Boolean Union (recommended)
or
Part Make compound (alternative choice)"""
+ # spc="""*******************************************************************************
+ # """
+ # msg1="Error in selection"
+ # QtGui.QApplication.restoreOverrideCursor()
+ ##RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
+ # diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical,
+ # msg1,
+ # msg)
+ # diag.setWindowModality(QtCore.Qt.ApplicationModal)
+ # diag.exec_()
+
+
### end get position
-def routineM_XYZ(axe,v):
+
+def routineM_XYZ(axe, v):
global resetP
- mydoc=FreeCAD.ActiveDocument
- say('routine Move to point XYZ')
- if 0:
- if "Assembly2Workbench" not in FreeCADGui.activeWorkbench().name():
- if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
- FreeCADGui.activateWorkbench("PartWorkbench")
- #FreeCADGui.SendMsgToActiveView("ViewFit")
+ say("routine Move to point XYZ")
+ if False:
+ if "PartWorkbench" not in FreeCADGui.activeWorkbench().name():
+ FreeCADGui.activateWorkbench("PartWorkbench")
+ # FreeCADGui.SendMsgToActiveView("ViewFit")
##FreeCADGui.activeDocument().activeView().viewTop()
doc = FreeCAD.ActiveDocument
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
if len(objs) == 1:
- doc.openTransaction('move')
+ doc.openTransaction("move")
check_AP()
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
s = objs[0].Shape
boundBox_ = s.BoundBox
- boundBoxLX = boundBox_.XLength
- boundBoxLY = boundBox_.YLength
- boundBoxLZ = boundBox_.ZLength
a = str(boundBox_)
- a,b = a.split('(')
- c = b.split(',')
+ a, b = a.split("(")
+ c = b.split(",")
oripl_X = float(c[0])
oripl_Y = float(c[1])
oripl_Z = float(c[2])
- shape=s.copy()
- shape.Placement=s.Placement;p=s.Placement
- #shape.rotate((oripl_X,oripl_Y,oripl_Z),(1,0,0),90)
- #say("axe "+axe+", value "+v)
- if axe=='x':
- #if abs(float(v)-p.Base[0])>min_val:
- shape.translate((float(v)-oripl_X,0,0))
- if axe=='y':
- shape.translate((0,float(v)-oripl_Y,0))
- if axe=='z':
- shape.translate((0,0,float(v)-oripl_Z))
- #Part.show(shape)
- objs[0].Placement=shape.Placement
+ shape = s.copy()
+ shape.Placement = s.Placement
+ # shape.rotate((oripl_X,oripl_Y,oripl_Z),(1,0,0),90)
+ # say("axe "+axe+", value "+v)
+ if axe == "x":
+ # if abs(float(v)-p.Base[0])>min_val:
+ shape.translate((float(v) - oripl_X, 0, 0))
+ if axe == "y":
+ shape.translate((0, float(v) - oripl_Y, 0))
+ if axe == "z":
+ shape.translate((0, 0, float(v) - oripl_Z))
+ # Part.show(shape)
+ objs[0].Placement = shape.Placement
FreeCADGui.Selection.addSelection(objs[0])
FreeCAD.activeDocument().recompute()
- if resetP==True:
+ if resetP:
routineResetPlacement()
doc.commitTransaction()
- #say("end of rotineM!")
+ # say("end of rotineM!")
else:
say(translate("Say", "Select an object !"))
- #QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
+ # QtGui.QMessageBox.information(None,"Info ...","Select ONE single part object !\r\n"+"\r\n")
+
+
### end Move to Point XYZ
-def recurse_app_part(ap,apl): # recursive function to get a list of Part objects contained in an AppPart obj
+
+def recurse_app_part(ap, apl): # recursive function to get a list of Part objects contained in an AppPart obj
if "App::Part" in ap.TypeId or "Body" in ap.TypeId:
for o in ap.Group:
- #sayw(o.Name)
+ # sayw(o.Name)
if "App::Part" in o.TypeId or "Body" in o.TypeId:
- recurse_app_part(o,apl)
+ recurse_app_part(o, apl)
elif "Sketch" not in o.TypeId:
- #print str(apl)
- #print o
- #if str(o.Name) not in str(apl):
+ # print str(apl)
+ # print o
+ # if str(o.Name) not in str(apl):
apl.append(o)
return apl
- elif "Compound" in ap.TypeId:
+ if "Compound" in ap.TypeId:
for e in ap.Links:
- if 'Compound' in e.Name:
- recurse_app_part(e,apl)
+ if "Compound" in e.Name:
+ recurse_app_part(e, apl)
else:
apl.append(e)
return apl
+ return None
+
+
##
+
def routineCollisions():
global conflict_tolerance
+
def error_dialog(msg):
"""Create a simple dialog QMessageBox with an error message"""
- FreeCAD.Console.PrintError(msg + '\n')
+ FreeCAD.Console.PrintError(msg + "\n")
QtGui.QApplication.restoreOverrideCursor()
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical,
- 'Error in checking Collisions ."+"\r\n"',
- msg)
+ diag = QtGui.QMessageBox(
+ QtGui.QMessageBox.Icon.Critical,
+ 'Error in checking Collisions ."+"\r\n"',
+ msg,
+ )
diag.setWindowModality(QtCore.Qt.ApplicationModal)
diag.exec_()
- #if len(FreeCADGui.Selection.getSelectionEx()) < 2:
+ # if len(FreeCADGui.Selection.getSelectionEx()) < 2:
if len(FreeCADGui.Selection.getSelection()) < 2:
- error_dialog('Select at least two objects')
- collisions=2
- return collisions
+ error_dialog("Select at least two objects")
+ return 2
object_list = []
object_names_list = []
- collisions=0
- #for obj in FreeCADGui.Selection.getSelectionEx():
+ collisions = 0
+ # for obj in FreeCADGui.Selection.getSelectionEx():
# object_list.append(obj.Object)
- n_objs=0
- apl=[]
+ n_objs = 0
+ apl = []
for obj in FreeCADGui.Selection.getSelection():
- #print obj.TypeId
- if ('Part' in obj.TypeId or 'App::Link' in obj.TypeId or 'App::LinkPython' in obj.TypeId) and 'App::Part' not in obj.TypeId and 'Compound' not in obj.TypeId and 'Body' not in obj.TypeId:
- #print obj.TypeId
- #object_list.append(obj)
- if obj.Name not in object_names_list:
- if hasattr(obj,"Placement"):
- object_list.append(obj)
- n_objs=n_objs+1
- #object_names_list.append(obj.Name)
- #n_objs=n_objs+1
- elif 'App::Part' in obj.TypeId or 'Compound' in obj.TypeId or 'Body' in obj.TypeId:
+ # print obj.TypeId
+ if (
+ ("Part" in obj.TypeId or "App::Link" in obj.TypeId or "App::LinkPython" in obj.TypeId)
+ and "App::Part" not in obj.TypeId
+ and "Compound" not in obj.TypeId
+ and "Body" not in obj.TypeId
+ ):
+ # print obj.TypeId
+ # object_list.append(obj)
+ if obj.Name not in object_names_list and hasattr(obj, "Placement"):
+ object_list.append(obj)
+ n_objs = n_objs + 1
+ # object_names_list.append(obj.Name)
+ # n_objs=n_objs+1
+ elif "App::Part" in obj.TypeId or "Compound" in obj.TypeId or "Body" in obj.TypeId:
# adding any single part of the group
- #say('recursing AppPart or Compound')
- apl=[]
- recurse_app_part(obj,apl)
- apl_names=[]
+ # say('recursing AppPart or Compound')
+ apl = []
+ recurse_app_part(obj, apl)
+ apl_names = []
for o in apl:
- #print o.Name,' ','apl'
+ # print o.Name,' ','apl'
##if o.Name not in apl_names:
- ##apl_names.append(o.Name)
+ ##apl_names.append(o.Name)
apl_names.append(o.Name)
- #print o.Name,' name appended'
- #print apl_names,' apl names'
+ # print o.Name,' name appended'
+ # print apl_names,' apl names'
for on in apl_names:
object_list.append(FreeCAD.ActiveDocument.getObject(on))
- n_objs=n_objs+1
- #print object_list
- #stop
+ n_objs = n_objs + 1
+ # print object_list
+ # stop
if n_objs < 2:
- error_dialog('Select at least two simple objects')
- collisions=2
- return collisions
+ error_dialog("Select at least two simple objects")
+ return 2
for i, object_a in enumerate(object_list):
- for object_b in object_list[(i + 1):]:
- say(make_string(object_a.Label)+" "+make_string(object_b.Label))
- if not hasattr(object_a,'Shape'): # use_Links
+ for object_b in object_list[(i + 1) :]:
+ say(make_string(object_a.Label) + " " + make_string(object_b.Label))
+ if not hasattr(object_a, "Shape"): # use_Links
shape_a = Part.getShape(object_a)
else:
shape_a = object_a.Shape
- #shape_a = object_a.Shape
- if not hasattr(object_b,'Shape'): # use_Links
+ # shape_a = object_a.Shape
+ if not hasattr(object_b, "Shape"): # use_Links
shape_b = Part.getShape(object_b)
else:
shape_b = object_b.Shape
- #shape_b = object_b.Shape
+ # shape_b = object_b.Shape
label_a = make_string(object_a.Label)
label_b = make_string(object_b.Label)
try:
## find the real position of the Part inside App::Part, then check collisions
if use_AppPart:
- #print object_a.InListRecursive
- #print object_b.InListRecursive
+ # print object_a.InListRecursive
+ # print object_b.InListRecursive
## copy objects and apply absolute placement to each one, then check collisions
- p0 = FreeCAD.Placement (FreeCAD.Vector(0,0,0), FreeCAD.Rotation(0,0,0), FreeCAD.Vector(0,0,0))
- pa_Original=shape_a.Placement
- s=shape_a
- #say('resetting props #2')
- r=[]
- t=s.copy()
+ FreeCAD.Placement(FreeCAD.Vector(0, 0, 0), FreeCAD.Rotation(0, 0, 0), FreeCAD.Vector(0, 0, 0))
+ s = shape_a
+ # say('resetting props #2')
+ r = []
+ t = s.copy()
for i in t.childShapes():
- c=i.copy()
- c.Placement=t.Placement.multiply(c.Placement)
- r.append((i,c))
- acpy=t.replaceShape(r)
- acpy.Placement=FreeCAD.Placement()
- #Part.show(acpy)
- #stop
- lrl=len(object_a.InListRecursive)
- #for o in object_a.InListRecursive:
+ c = i.copy()
+ c.Placement = t.Placement.multiply(c.Placement)
+ r.append((i, c))
+ acpy = t.replaceShape(r)
+ acpy.Placement = FreeCAD.Placement()
+ # Part.show(acpy)
+ # stop
+ lrl = len(object_a.InListRecursive)
+ # for o in object_a.InListRecursive:
# say(o.Name)
- inverted=True
+ inverted = True
if len(object_a.InList):
if object_a.InListRecursive[0].Name == object_a.InList[0].Name:
- inverted=False
+ inverted = False
if inverted:
- for i in range (0,lrl):
- if hasattr(object_a.InListRecursive[i],'Placement'):
- acpy.Placement=acpy.Placement.multiply(object_a.InListRecursive[i].Placement)
+ for i in range(lrl):
+ if hasattr(object_a.InListRecursive[i], "Placement"):
+ acpy.Placement = acpy.Placement.multiply(object_a.InListRecursive[i].Placement)
else:
- for i in range (0,lrl):
- if hasattr(object_a.InListRecursive[i],'Placement'):
- acpy.Placement=acpy.Placement.multiply(object_a.InListRecursive[lrl-1-i].Placement)
- #acpy.Placement=acpy.Placement.multiply(pa_Original)
- # Part.show(acpy)
+ for i in range(lrl):
+ if hasattr(object_a.InListRecursive[i], "Placement"):
+ acpy.Placement = acpy.Placement.multiply(
+ object_a.InListRecursive[lrl - 1 - i].Placement,
+ )
+ # acpy.Placement=acpy.Placement.multiply(pa_Original)
+ # Part.show(acpy)
# stop
- pb_Original=shape_b.Placement
- s=shape_b
- #say('resetting props #2')
- r=[]
- t=s.copy()
+ s = shape_b
+ # say('resetting props #2')
+ r = []
+ t = s.copy()
for i in t.childShapes():
- c=i.copy()
- c.Placement=t.Placement.multiply(c.Placement)
- r.append((i,c))
- bcpy=t.replaceShape(r)
- bcpy.Placement=FreeCAD.Placement()
- lrl=len(object_b.InListRecursive)
+ c = i.copy()
+ c.Placement = t.Placement.multiply(c.Placement)
+ r.append((i, c))
+ bcpy = t.replaceShape(r)
+ bcpy.Placement = FreeCAD.Placement()
+ lrl = len(object_b.InListRecursive)
if len(object_b.InList):
if object_b.InListRecursive[0].Name == object_b.InList[0].Name:
- inverted=False
+ inverted = False
if inverted:
- for i in range (0,lrl):
- if hasattr(object_b.InListRecursive[i],'Placement'):
- bcpy.Placement=bcpy.Placement.multiply(object_b.InListRecursive[i].Placement)
+ for i in range(lrl):
+ if hasattr(object_b.InListRecursive[i], "Placement"):
+ bcpy.Placement = bcpy.Placement.multiply(object_b.InListRecursive[i].Placement)
else:
- for i in range (0,lrl):
- if hasattr(object_b.InListRecursive[i],'Placement'):
- bcpy.Placement=bcpy.Placement.multiply(object_b.InListRecursive[lrl-1-i].Placement)
- #Part.show(bcpy)
+ for i in range(lrl):
+ if hasattr(object_b.InListRecursive[i], "Placement"):
+ bcpy.Placement = bcpy.Placement.multiply(
+ object_b.InListRecursive[lrl - 1 - i].Placement,
+ )
+ # Part.show(bcpy)
common = acpy.common(bcpy)
- #FreeCAD.ActiveDocument.removeObject(acpy)
- #FreeCAD.ActiveDocument.removeObject(bcpy)
+ # FreeCAD.ActiveDocument.removeObject(acpy)
+ # FreeCAD.ActiveDocument.removeObject(bcpy)
FreeCAD.ActiveDocument.recompute()
- #stop
- ##try:
- ## ## find the real position of the Part inside App::Part, then check collisions
- ## ## print object_a.InListRecursive
- ## ##
- ## #b=App.ActiveDocument.addObject("Part::Box","Box")
- ## if use_AppPart:
- ## acpy= FreeCAD.ActiveDocument.copyObject(object_a,False)
- ## bcpy= FreeCAD.ActiveDocument.copyObject(object_b,False)
- ## #shape=acpy.Shape.copy()
- ## #shape.Placement=acpy.Placement
- ## #impPart.Placement=shape.Placement;
- ## ## copy objects and apply absolute placement to each one, then check collisions
- ## for o in object_b.InListRecursive:
- ## acpy.Placement=acpy.Placement.multiply(o.Placement)
- ## #Part.show(shape)
- ## #acpy.Placement=shape.Placement
- ## #stop
- ## #lr=len(object_a.InListRecursive)
- ## #for i in range(lr-1,-1,-1):
- ## # print object_a.InListRecursive[i].Label
- ## # #print get_node_plc(object_a.InListRecursive[i],acpy)
- ## # shape.Placement=shape.Placement.multiply(object_a.InListRecursive[i].Placement)
- ## # #acpy.Placement=acpy.Placement.multiply(object_a.InListRecursive[i].Placement)
- ## #acpy.Placement=shape.Placement
- ## #stop
- ## for o in object_b.InListRecursive:
- ## bcpy.Placement=bcpy.Placement.multiply(o.Placement)
- ## #print 'doing'
- ## #print bcpy.Name, 'here'
- ## common = acpy.Shape.common(bcpy.Shape)
- ## #FreeCAD.ActiveDocument.removeObject(acpy.Name)
- ## #FreeCAD.ActiveDocument.removeObject(bcpy.Name)
- ## #FreeCAD.ActiveDocument.recompute()
- ## #stop
+ # stop
+ ##try:
+ ## ## find the real position of the Part inside App::Part, then check collisions
+ ## ## print object_a.InListRecursive
+ ## ##
+ ## #b=App.ActiveDocument.addObject("Part::Box","Box")
+ ## if use_AppPart:
+ ## acpy= FreeCAD.ActiveDocument.copyObject(object_a,False)
+ ## bcpy= FreeCAD.ActiveDocument.copyObject(object_b,False)
+ ## #shape=acpy.Shape.copy()
+ ## #shape.Placement=acpy.Placement
+ ## #impPart.Placement=shape.Placement;
+ ## ## copy objects and apply absolute placement to each one, then check collisions
+ ## for o in object_b.InListRecursive:
+ ## acpy.Placement=acpy.Placement.multiply(o.Placement)
+ ## #Part.show(shape)
+ ## #acpy.Placement=shape.Placement
+ ## #stop
+ ## #lr=len(object_a.InListRecursive)
+ ## #for i in range(lr-1,-1,-1):
+ ## # print object_a.InListRecursive[i].Label
+ ## # #print get_node_plc(object_a.InListRecursive[i],acpy)
+ ## # shape.Placement=shape.Placement.multiply(object_a.InListRecursive[i].Placement)
+ ## # #acpy.Placement=acpy.Placement.multiply(object_a.InListRecursive[i].Placement)
+ ## #acpy.Placement=shape.Placement
+ ## #stop
+ ## for o in object_b.InListRecursive:
+ ## bcpy.Placement=bcpy.Placement.multiply(o.Placement)
+ ## #print 'doing'
+ ## #print bcpy.Name, 'here'
+ ## common = acpy.Shape.common(bcpy.Shape)
+ ## #FreeCAD.ActiveDocument.removeObject(acpy.Name)
+ ## #FreeCAD.ActiveDocument.removeObject(bcpy.Name)
+ ## #FreeCAD.ActiveDocument.recompute()
+ ## #stop
else:
common = shape_a.common(shape_b)
- #d = shape_a.distToShape(shape_b)
- #sayw(d)
- #sayerr(d[0])
+ # d = shape_a.distToShape(shape_b)
+ # sayw(d)
+ # sayerr(d[0])
if common.Volume > conflict_tolerance:
- say(
- 'Volume of the intersection between {} and {}: {}\n'.format(
- label_a,
- label_b,
- common.Volume))
- redundant=False
+ say(f"Volume of the intersection between {label_a} and {label_b}: {common.Volume}\n")
+ redundant = False
for o in FreeCAD.ActiveDocument.Objects:
- if make_string(o.Label) == 'Collisions ({} - {})'.format(label_a, label_b):
- sayw('collision redundant')
- redundant=True
+ if make_string(o.Label) == f"Collisions ({label_a} - {label_b})":
+ sayw("collision redundant")
+ redundant = True
if not redundant:
- intersection_object = FreeCAD.ActiveDocument.addObject(
- 'Part::Feature')
- intersection_object.Label = 'Collisions ({} - {})'.format(
- label_a, label_b)
+ intersection_object = FreeCAD.ActiveDocument.addObject("Part::Feature")
+ intersection_object.Label = f"Collisions ({label_a} - {label_b})"
intersection_object.Shape = common
## print object_a.InListRecursive
## for o in object_a.InListRecursive:
## intersection_object.Placement=intersection_object.Placement.multiply(o.Placement)
## print o.Name
-
+
## bg=App.ActiveDocument.getObject('Board')
## intersection_object.Placement=bg.Placement.multiply(common.Placement)
intersection_object.ViewObject.ShapeColor = (1.0, 0.0, 0.0, 1.0)
- #object_a.ViewObject.Transparency = 80
- #object_b.ViewObject.Transparency = 80
- #object_a.ViewObject.Visibility=False
- #object_b.ViewObject.Visibility=False
+ # object_a.ViewObject.Transparency = 80
+ # object_b.ViewObject.Transparency = 80
+ # object_a.ViewObject.Visibility=False
+ # object_b.ViewObject.Visibility=False
sel1 = FreeCADGui.Selection.getSelection()
for e in sel1:
- FreeCADGui.ActiveDocument.getObject(e.Name).Visibility=False
+ FreeCADGui.ActiveDocument.getObject(e.Name).Visibility = False
##for e in FreeCAD.ActiveDocument.Objects:
## if 'Compound' in e.TypeId:
## if object_a in e.Links or object_b in e.Links:
@@ -8391,63 +9021,71 @@ def error_dialog(msg):
## #print a.Group, e
## if e in a.Group and: e not in sel1:
## FreeCADGui.ActiveDocument.getObject(e.Name).Visibility=True
- collisions=1
+ collisions = 1
else:
- say(
- 'No intersection between {} and {}\n'.format(
- label_a,
- label_b))
- #collisions=0
+ say(f"No intersection between {label_a} and {label_b}\n")
+ # collisions=0
except Exception as e:
- FreeCAD.Console.PrintWarning(u"{0}\n".format(e))
- #say("here_collision\r\n")
+ FreeCAD.Console.PrintWarning(f"{e}\n")
+ # say("here_collision\r\n")
return collisions
+
### end Collisions
+
def create_axis():
global disablePoM_Observer
if disable_PoM_Observer:
- #paramGetPoM = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/PartOMagic")
- #PoMObs_status=paramGetPoM.GetBool("EnableObserver")
+ # paramGetPoM = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/PartOMagic")
+ # PoMObs_status=paramGetPoM.GetBool("EnableObserver")
PoMObs_status = False
if Observer.isRunning():
- PoMObs_status=True
- #if PoMObs_status:
+ PoMObs_status = True
+ # if PoMObs_status:
Observer.stop()
sayw("disabling PoM Observer")
FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", "axis")
- #Z axis
- FreeCAD.ActiveDocument.addObject("Part::Box","AxisBoxZ")
+ # Z axis
+ FreeCAD.ActiveDocument.addObject("Part::Box", "AxisBoxZ")
FreeCAD.ActiveDocument.ActiveObject.Label = "CubeZ"
- FreeCAD.ActiveDocument.addObject("Part::Cone","AxisConeZ")
+ FreeCAD.ActiveDocument.addObject("Part::Cone", "AxisConeZ")
FreeCAD.ActiveDocument.ActiveObject.Label = "ConeZ"
- FreeCAD.ActiveDocument.getObject("AxisBoxZ").Width = '0 mm'
- FreeCAD.ActiveDocument.getObject("AxisBoxZ").Width = '0.1 mm'
- FreeCAD.ActiveDocument.getObject("AxisBoxZ").Length = '0 mm'
- FreeCAD.ActiveDocument.getObject("AxisBoxZ").Length = '0.2 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeZ").Radius1 = '0 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeZ").Radius1 = '0.4 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeZ").Radius2 = '0 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeZ").Radius2 = '0.1 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeZ").Placement = FreeCAD.Placement(FreeCAD.Vector(0,0,9),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- FreeCAD.ActiveDocument.getObject("AxisConeZ").Height = '5 mm'
- FreeCAD.ActiveDocument.getObject("AxisBoxZ").Placement = FreeCAD.Placement(FreeCAD.Vector(-0.1,-0.05,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- FreeCADGui.ActiveDocument.getObject("AxisConeZ").ShapeColor = (0.0000,0.0000,1.0000)
- FreeCADGui.ActiveDocument.getObject("AxisBoxZ").ShapeColor = (0.0000,0.0000,1.0000)
- FreeCAD.activeDocument().addObject("Part::MultiFuse","FusionAxisZ")
- FreeCAD.activeDocument().FusionAxisZ.Shapes = [FreeCAD.activeDocument().AxisBoxZ,FreeCAD.activeDocument().AxisConeZ,]
- FreeCADGui.activeDocument().AxisBoxZ.Visibility=False
- FreeCADGui.activeDocument().AxisConeZ.Visibility=False
- FreeCADGui.ActiveDocument.FusionAxisZ.ShapeColor=FreeCADGui.ActiveDocument.AxisBoxZ.ShapeColor
- FreeCADGui.ActiveDocument.FusionAxisZ.DisplayMode=FreeCADGui.ActiveDocument.AxisBoxZ.DisplayMode
+ FreeCAD.ActiveDocument.getObject("AxisBoxZ").Width = "0 mm"
+ FreeCAD.ActiveDocument.getObject("AxisBoxZ").Width = "0.1 mm"
+ FreeCAD.ActiveDocument.getObject("AxisBoxZ").Length = "0 mm"
+ FreeCAD.ActiveDocument.getObject("AxisBoxZ").Length = "0.2 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeZ").Radius1 = "0 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeZ").Radius1 = "0.4 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeZ").Radius2 = "0 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeZ").Radius2 = "0.1 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeZ").Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, 0, 9),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0),
+ )
+ FreeCAD.ActiveDocument.getObject("AxisConeZ").Height = "5 mm"
+ FreeCAD.ActiveDocument.getObject("AxisBoxZ").Placement = FreeCAD.Placement(
+ FreeCAD.Vector(-0.1, -0.05, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0),
+ )
+ FreeCADGui.ActiveDocument.getObject("AxisConeZ").ShapeColor = (0.0000, 0.0000, 1.0000)
+ FreeCADGui.ActiveDocument.getObject("AxisBoxZ").ShapeColor = (0.0000, 0.0000, 1.0000)
+ FreeCAD.activeDocument().addObject("Part::MultiFuse", "FusionAxisZ")
+ FreeCAD.activeDocument().FusionAxisZ.Shapes = [
+ FreeCAD.activeDocument().AxisBoxZ,
+ FreeCAD.activeDocument().AxisConeZ,
+ ]
+ FreeCADGui.activeDocument().AxisBoxZ.Visibility = False
+ FreeCADGui.activeDocument().AxisConeZ.Visibility = False
+ FreeCADGui.ActiveDocument.FusionAxisZ.ShapeColor = FreeCADGui.ActiveDocument.AxisBoxZ.ShapeColor
+ FreeCADGui.ActiveDocument.FusionAxisZ.DisplayMode = FreeCADGui.ActiveDocument.AxisBoxZ.DisplayMode
FreeCAD.ActiveDocument.recompute()
- FreeCAD.ActiveDocument.addObject('Part::Feature','FusionAxisZ1').Shape=FreeCAD.ActiveDocument.FusionAxisZ.Shape
+ FreeCAD.ActiveDocument.addObject("Part::Feature", "FusionAxisZ1").Shape = FreeCAD.ActiveDocument.FusionAxisZ.Shape
FreeCAD.ActiveDocument.ActiveObject.Label = "Z"
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=(0.0000,0.0000,1.0000)
- obj=FreeCAD.ActiveDocument.ActiveObject
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.0000, 0.0000, 1.0000)
+ obj = FreeCAD.ActiveDocument.ActiveObject
FreeCAD.ActiveDocument.getObject("axis").addObject(obj)
FreeCAD.ActiveDocument.recompute()
FreeCAD.ActiveDocument.removeObject("FusionAxisZ")
@@ -8455,262 +9093,333 @@ def create_axis():
FreeCAD.ActiveDocument.removeObject("AxisConeZ")
FreeCAD.ActiveDocument.recompute()
- #Y axis
- FreeCAD.ActiveDocument.addObject("Part::Box","AxisBoxY")
+ # Y axis
+ FreeCAD.ActiveDocument.addObject("Part::Box", "AxisBoxY")
FreeCAD.ActiveDocument.ActiveObject.Label = "CubeY"
- FreeCAD.ActiveDocument.addObject("Part::Cone","AxisConeY")
+ FreeCAD.ActiveDocument.addObject("Part::Cone", "AxisConeY")
FreeCAD.ActiveDocument.ActiveObject.Label = "ConeY"
- FreeCAD.ActiveDocument.getObject("AxisBoxY").Width = '0 mm'
- FreeCAD.ActiveDocument.getObject("AxisBoxY").Width = '0.1 mm'
- FreeCAD.ActiveDocument.getObject("AxisBoxY").Length = '0 mm'
- FreeCAD.ActiveDocument.getObject("AxisBoxY").Length = '0.2 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeY").Radius1 = '0 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeY").Radius1 = '0.4 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeY").Radius2 = '0 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeY").Radius2 = '0.1 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeY").Placement = FreeCAD.Placement(FreeCAD.Vector(0,0,9),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- FreeCAD.ActiveDocument.getObject("AxisConeY").Height = '5 mm'
- FreeCAD.ActiveDocument.getObject("AxisBoxY").Placement = FreeCAD.Placement(FreeCAD.Vector(-0.1,-0.05,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- FreeCADGui.ActiveDocument.getObject("AxisConeY").ShapeColor = (0.0000,1.0000,0.0000)
- FreeCADGui.ActiveDocument.getObject("AxisBoxY").ShapeColor = (0.0000,1.0000,0.0000)
- FreeCAD.activeDocument().addObject("Part::MultiFuse","FusionAxisY")
- FreeCAD.activeDocument().FusionAxisY.Shapes = [FreeCAD.activeDocument().AxisBoxY,FreeCAD.activeDocument().AxisConeY,]
- FreeCADGui.activeDocument().AxisBoxY.Visibility=False
- FreeCADGui.activeDocument().AxisConeY.Visibility=False
- FreeCADGui.ActiveDocument.FusionAxisY.ShapeColor=FreeCADGui.ActiveDocument.AxisBoxY.ShapeColor
- FreeCADGui.ActiveDocument.FusionAxisY.DisplayMode=FreeCADGui.ActiveDocument.AxisBoxY.DisplayMode
+ FreeCAD.ActiveDocument.getObject("AxisBoxY").Width = "0 mm"
+ FreeCAD.ActiveDocument.getObject("AxisBoxY").Width = "0.1 mm"
+ FreeCAD.ActiveDocument.getObject("AxisBoxY").Length = "0 mm"
+ FreeCAD.ActiveDocument.getObject("AxisBoxY").Length = "0.2 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeY").Radius1 = "0 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeY").Radius1 = "0.4 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeY").Radius2 = "0 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeY").Radius2 = "0.1 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeY").Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, 0, 9),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0),
+ )
+ FreeCAD.ActiveDocument.getObject("AxisConeY").Height = "5 mm"
+ FreeCAD.ActiveDocument.getObject("AxisBoxY").Placement = FreeCAD.Placement(
+ FreeCAD.Vector(-0.1, -0.05, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0),
+ )
+ FreeCADGui.ActiveDocument.getObject("AxisConeY").ShapeColor = (0.0000, 1.0000, 0.0000)
+ FreeCADGui.ActiveDocument.getObject("AxisBoxY").ShapeColor = (0.0000, 1.0000, 0.0000)
+ FreeCAD.activeDocument().addObject("Part::MultiFuse", "FusionAxisY")
+ FreeCAD.activeDocument().FusionAxisY.Shapes = [
+ FreeCAD.activeDocument().AxisBoxY,
+ FreeCAD.activeDocument().AxisConeY,
+ ]
+ FreeCADGui.activeDocument().AxisBoxY.Visibility = False
+ FreeCADGui.activeDocument().AxisConeY.Visibility = False
+ FreeCADGui.ActiveDocument.FusionAxisY.ShapeColor = FreeCADGui.ActiveDocument.AxisBoxY.ShapeColor
+ FreeCADGui.ActiveDocument.FusionAxisY.DisplayMode = FreeCADGui.ActiveDocument.AxisBoxY.DisplayMode
FreeCAD.ActiveDocument.recompute()
- FreeCAD.ActiveDocument.addObject('Part::Feature','FusionAxisY1').Shape=FreeCAD.ActiveDocument.FusionAxisY.Shape
+ FreeCAD.ActiveDocument.addObject("Part::Feature", "FusionAxisY1").Shape = FreeCAD.ActiveDocument.FusionAxisY.Shape
FreeCAD.ActiveDocument.ActiveObject.Label = "Y"
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=(0.0000,1.0000,0.000)
- obj=FreeCAD.ActiveDocument.ActiveObject
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.0000, 1.0000, 0.000)
+ obj = FreeCAD.ActiveDocument.ActiveObject
FreeCAD.ActiveDocument.getObject("axis").addObject(obj)
FreeCAD.ActiveDocument.recompute()
FreeCAD.ActiveDocument.removeObject("FusionAxisY")
FreeCAD.ActiveDocument.removeObject("AxisBoxY")
FreeCAD.ActiveDocument.removeObject("AxisConeY")
FreeCAD.ActiveDocument.recompute()
- FreeCAD.ActiveDocument.ActiveObject.Placement = FreeCAD.Placement(FreeCAD.Vector(0,0,0.05),FreeCAD.Rotation(FreeCAD.Vector(1,0,0),-90))
+ FreeCAD.ActiveDocument.ActiveObject.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, 0, 0.05),
+ FreeCAD.Rotation(FreeCAD.Vector(1, 0, 0), -90),
+ )
- #X axis
- FreeCAD.ActiveDocument.addObject("Part::Box","AxisBoxX")
+ # X axis
+ FreeCAD.ActiveDocument.addObject("Part::Box", "AxisBoxX")
FreeCAD.ActiveDocument.ActiveObject.Label = "CubeX"
- FreeCAD.ActiveDocument.addObject("Part::Cone","AxisConeX")
+ FreeCAD.ActiveDocument.addObject("Part::Cone", "AxisConeX")
FreeCAD.ActiveDocument.ActiveObject.Label = "ConeX"
- FreeCAD.ActiveDocument.getObject("AxisBoxX").Width = '0 mm'
- FreeCAD.ActiveDocument.getObject("AxisBoxX").Width = '0.2 mm'
- FreeCAD.ActiveDocument.getObject("AxisBoxX").Length = '0 mm'
- FreeCAD.ActiveDocument.getObject("AxisBoxX").Length = '0.1 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeX").Radius1 = '0 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeX").Radius1 = '0.4 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeX").Radius2 = '0 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeX").Radius2 = '0.1 mm'
- FreeCAD.ActiveDocument.getObject("AxisConeX").Placement = FreeCAD.Placement(FreeCAD.Vector(0,0,9),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- FreeCAD.ActiveDocument.getObject("AxisConeX").Height = '5 mm'
- FreeCAD.ActiveDocument.getObject("AxisBoxX").Placement = FreeCAD.Placement(FreeCAD.Vector(-0.1,-0.05,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
- FreeCADGui.ActiveDocument.getObject("AxisConeX").ShapeColor = (1.0000,0.0000,0.0000)
- FreeCADGui.ActiveDocument.getObject("AxisBoxX").ShapeColor = (1.0000,0.0000,0.0000)
- FreeCAD.activeDocument().addObject("Part::MultiFuse","FusionAxisX")
- FreeCAD.activeDocument().FusionAxisX.Shapes = [FreeCAD.activeDocument().AxisBoxX,FreeCAD.activeDocument().AxisConeX,]
- FreeCADGui.activeDocument().AxisBoxX.Visibility=False
- FreeCADGui.activeDocument().AxisConeX.Visibility=False
- FreeCADGui.ActiveDocument.FusionAxisX.ShapeColor=FreeCADGui.ActiveDocument.AxisBoxX.ShapeColor
- FreeCADGui.ActiveDocument.FusionAxisX.DisplayMode=FreeCADGui.ActiveDocument.AxisBoxX.DisplayMode
+ FreeCAD.ActiveDocument.getObject("AxisBoxX").Width = "0 mm"
+ FreeCAD.ActiveDocument.getObject("AxisBoxX").Width = "0.2 mm"
+ FreeCAD.ActiveDocument.getObject("AxisBoxX").Length = "0 mm"
+ FreeCAD.ActiveDocument.getObject("AxisBoxX").Length = "0.1 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeX").Radius1 = "0 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeX").Radius1 = "0.4 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeX").Radius2 = "0 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeX").Radius2 = "0.1 mm"
+ FreeCAD.ActiveDocument.getObject("AxisConeX").Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, 0, 9),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0),
+ )
+ FreeCAD.ActiveDocument.getObject("AxisConeX").Height = "5 mm"
+ FreeCAD.ActiveDocument.getObject("AxisBoxX").Placement = FreeCAD.Placement(
+ FreeCAD.Vector(-0.1, -0.05, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 0),
+ )
+ FreeCADGui.ActiveDocument.getObject("AxisConeX").ShapeColor = (1.0000, 0.0000, 0.0000)
+ FreeCADGui.ActiveDocument.getObject("AxisBoxX").ShapeColor = (1.0000, 0.0000, 0.0000)
+ FreeCAD.activeDocument().addObject("Part::MultiFuse", "FusionAxisX")
+ FreeCAD.activeDocument().FusionAxisX.Shapes = [
+ FreeCAD.activeDocument().AxisBoxX,
+ FreeCAD.activeDocument().AxisConeX,
+ ]
+ FreeCADGui.activeDocument().AxisBoxX.Visibility = False
+ FreeCADGui.activeDocument().AxisConeX.Visibility = False
+ FreeCADGui.ActiveDocument.FusionAxisX.ShapeColor = FreeCADGui.ActiveDocument.AxisBoxX.ShapeColor
+ FreeCADGui.ActiveDocument.FusionAxisX.DisplayMode = FreeCADGui.ActiveDocument.AxisBoxX.DisplayMode
FreeCAD.ActiveDocument.recompute()
- FreeCAD.ActiveDocument.addObject('Part::Feature','FusionAxisX1').Shape=FreeCAD.ActiveDocument.FusionAxisX.Shape
- FreeCAD.ActiveDocument.ActiveObject.Label="X"
+ FreeCAD.ActiveDocument.addObject("Part::Feature", "FusionAxisX1").Shape = FreeCAD.ActiveDocument.FusionAxisX.Shape
+ FreeCAD.ActiveDocument.ActiveObject.Label = "X"
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=(1.0000,0.0000,0.0000)
- obj=FreeCAD.ActiveDocument.ActiveObject
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (1.0000, 0.0000, 0.0000)
+ obj = FreeCAD.ActiveDocument.ActiveObject
FreeCAD.ActiveDocument.getObject("axis").addObject(obj)
FreeCAD.ActiveDocument.recompute()
FreeCAD.ActiveDocument.removeObject("FusionAxisX")
FreeCAD.ActiveDocument.removeObject("AxisBoxX")
FreeCAD.ActiveDocument.removeObject("AxisConeX")
- FreeCAD.ActiveDocument.getObject("FusionAxisX1").Placement = FreeCAD.Placement(FreeCAD.Vector(0,-0.05,0),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90))
+ FreeCAD.ActiveDocument.getObject("FusionAxisX1").Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, -0.05, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 1, 0), 90),
+ )
FreeCAD.ActiveDocument.recompute()
- if disable_PoM_Observer:
- if PoMObs_status:
- Observer.start()
- sayw("enabling PoM Observer")
-
+ if disable_PoM_Observer and PoMObs_status:
+ Observer.start()
+ sayw("enabling PoM Observer")
+
+
###
#############################
def createSolidBBox2(model3D):
- #FreeCADGui.Selection.removeSelection(FreeCAD.activeDocument().ActiveObject)
- selEx=model3D
+ # FreeCADGui.Selection.removeSelection(FreeCAD.activeDocument().ActiveObject)
+ selEx = model3D
selEx = FreeCADGui.Selection.getSelectionEx()
objs = [selobj.Object for selobj in selEx]
if len(objs) == 1:
s = objs[0].Shape
- name=objs[0].Label
- #say(name+" name")
+ name = objs[0].Label
+ # say(name+" name")
# boundBox
- delta=0.6
+ delta = 0.6
boundBox_ = s.BoundBox
- boundBoxLX = boundBox_.XLength*(1+delta)
- boundBoxLY = boundBox_.YLength*(1+delta)
- #boundBoxLZ = boundBox_.ZLength
+ boundBoxLX = boundBox_.XLength * (1 + delta)
+ boundBoxLY = boundBox_.YLength * (1 + delta)
+ # boundBoxLZ = boundBox_.ZLength
boundBoxLZ = 1.58
- offX=boundBox_.XLength*(-delta)/2
- offY=boundBox_.YLength*(-delta)/2
- offZ=-0.01
+ offX = boundBox_.XLength * (-delta) / 2
+ offY = boundBox_.YLength * (-delta) / 2
+ offZ = -0.01
a = str(boundBox_)
- a,b = a.split('(')
- c = b.split(',')
- oripl_X = float(c[0])+offX
- oripl_Y = float(c[1])+offY
- #oripl_Z = float(c[2])+offZ
- oripl_Z = -boundBoxLZ+offZ
-
- #say(str(boundBox_))
- #say("Rectangle : "+str(boundBox_.XLength)+" x "+str(boundBox_.YLength)+" x "+str(boundBox_.ZLength))
- #say("_____________________")
- #say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
-
- obj=FreeCAD.ActiveDocument.addObject('Part::Feature',name)
- #obj.Shape=Part.makeBox(boundBox_.XLength, boundBox_.YLength, boundBox_.ZLength, FreeCAD.Vector(oripl_X,oripl_Y,oripl_Z), FreeCAD.Vector(0,0,01))
- #obj.Shape=Part.makeBox(boundBoxLX, boundBoxLY, boundBoxLZ, FreeCAD.Vector(oripl_X,oripl_Y,oripl_Z), FreeCAD.Vector(0,0,01))
- obj.Shape=Part.makeBox(boundBoxLX, boundBoxLY, boundBoxLZ, FreeCAD.Vector(oripl_X,oripl_Y,oripl_Z), FreeCAD.Vector(0,0,1))
-
- #obj.translate(offX,offY,0)
+ a, b = a.split("(")
+ c = b.split(",")
+ oripl_X = float(c[0]) + offX
+ oripl_Y = float(c[1]) + offY
+ # oripl_Z = float(c[2])+offZ
+ oripl_Z = -boundBoxLZ + offZ
+
+ # say(str(boundBox_))
+ # say("Rectangle : "+str(boundBox_.XLength)+" x "+str(boundBox_.YLength)+" x "+str(boundBox_.ZLength))
+ # say("_____________________")
+ # say("x: "+str(oripl_X)+" y: "+str(oripl_Y)+"z: "+str(oripl_Z))
+
+ obj = FreeCAD.ActiveDocument.addObject("Part::Feature", name)
+ # obj.Shape=Part.makeBox(boundBox_.XLength, boundBox_.YLength, boundBox_.ZLength, FreeCAD.Vector(oripl_X,oripl_Y,oripl_Z), FreeCAD.Vector(0,0,01))
+ # obj.Shape=Part.makeBox(boundBoxLX, boundBoxLY, boundBoxLZ, FreeCAD.Vector(oripl_X,oripl_Y,oripl_Z), FreeCAD.Vector(0,0,01))
+ obj.Shape = Part.makeBox(
+ boundBoxLX,
+ boundBoxLY,
+ boundBoxLZ,
+ FreeCAD.Vector(oripl_X, oripl_Y, oripl_Z),
+ FreeCAD.Vector(0, 0, 1),
+ )
+
+ # obj.translate(offX,offY,0)
# Part.show(cube)
- #say("cube name "+ obj.Name)
+ # say("cube name "+ obj.Name)
### FreeCAD.ActiveDocument.recompute()
else:
say("Select a single part object !")
- #end bbox macro
+ # end bbox macro
- name=obj.Name
- #say("bbox name "+name)
+ name = obj.Name
+ # say("bbox name "+name)
del objs
return name
+
###
def rotateObj(mainObj, rot):
return mainObj.rotate(FreeCAD.Vector(rot[0], rot[1], 0), FreeCAD.Vector(0, 0, 1), rot[2])
+
+
###
def rotateObjs(listObjs, rot):
- #listObjs.rotate(FreeCAD.Vector(rot[0], rot[1], 0), FreeCAD.Vector(0, 0, 1), rot[2])
- Draft.rotate(listObjs,rot[2],FreeCAD.Vector(rot[0],rot[1],0.0),axis=FreeCAD.Vector(0.0,0.0,1.0),copy=False)
+ # listObjs.rotate(FreeCAD.Vector(rot[0], rot[1], 0), FreeCAD.Vector(0, 0, 1), rot[2])
+ Draft.rotate(listObjs, rot[2], FreeCAD.Vector(rot[0], rot[1], 0.0), axis=FreeCAD.Vector(0.0, 0.0, 1.0), copy=False)
+
+
###
def changeSide(self, mainObj, X1, Y1, top):
- if top == 0: #to bot side
+ if top == 0: # to bot side
mainObj.rotate(FreeCAD.Vector(X1, Y1, 0), FreeCAD.Vector(0, 1, 0), 180)
+
+
###
def arcMidPoint(prev_vertex, vertex, angle):
if len(prev_vertex) == 3:
- [x1, y1, z1] = prev_vertex
+ [x1, y1, _z1] = prev_vertex
else:
[x1, y1] = prev_vertex
if len(vertex) == 3:
- [x2, y2, z2] = vertex
+ [x2, y2, _z2] = vertex
else:
[x2, y2] = vertex
angle = radians(angle / 2)
basic_angle = atan2(y2 - y1, x2 - x1) - pi / 2
shift = (1 - cos(angle)) * hypot(y2 - y1, x2 - x1) / 2 / sin(angle)
- midpoint = [(x2 + x1) / 2 + shift * cos(basic_angle), (y2 + y1) / 2 + shift * sin(basic_angle)]
+ return [(x2 + x1) / 2 + shift * cos(basic_angle), (y2 + y1) / 2 + shift * sin(basic_angle)]
- return midpoint
###
+
def sinus(angle):
- return float("%4.10f" % sin(radians(angle)))
+ return float(f"{sin(radians(angle)):4.10f}")
+
def cosinus(angle):
- return float("%4.10f" % cos(radians(angle)))
+ return float(f"{cos(radians(angle)):4.10f}")
+
def arcCenter(x1, y1, x2, y2, x3, y3):
- Xs = 0.5 * (x2 * x2 * y3 + y2 * y2 * y3 - x1 * x1 * y3 + x1 * x1 * y2 - y1 * y1 * y3 + y1 * y1 * y2 + y1 * x3 * x3 + y1 * y3 * y3 - y1 * x2 * x2 - y1 * y2 * y2 - y2 * x3 * x3 - y2 * y3 * y3) / (y1 * x3 - y1 * x2 - y2 * x3 - y3 * x1 + y3 * x2 + y2 * x1)
- Ys = 0.5 * (-x1 * x3 * x3 - x1 * y3 * y3 + x1 * x2 * x2 + x1 * y2 * y2 + x2 * x3 * x3 + x2 * y3 * y3 - x2 * x2 * x3 - y2 * y2 * x3 + x1 * x1 * x3 - x1 * x1 * x2 + y1 * y1 * x3 - y1 * y1 * x2) / (y1 * x3 - y1 * x2 - y2 * x3 - y3 * x1 + y3 * x2 + y2 * x1)
+ Xs = (
+ 0.5
+ * (
+ x2 * x2 * y3
+ + y2 * y2 * y3
+ - x1 * x1 * y3
+ + x1 * x1 * y2
+ - y1 * y1 * y3
+ + y1 * y1 * y2
+ + y1 * x3 * x3
+ + y1 * y3 * y3
+ - y1 * x2 * x2
+ - y1 * y2 * y2
+ - y2 * x3 * x3
+ - y2 * y3 * y3
+ )
+ / (y1 * x3 - y1 * x2 - y2 * x3 - y3 * x1 + y3 * x2 + y2 * x1)
+ )
+ Ys = (
+ 0.5
+ * (
+ -x1 * x3 * x3
+ - x1 * y3 * y3
+ + x1 * x2 * x2
+ + x1 * y2 * y2
+ + x2 * x3 * x3
+ + x2 * y3 * y3
+ - x2 * x2 * x3
+ - y2 * y2 * x3
+ + x1 * x1 * x3
+ - x1 * x1 * x2
+ + y1 * y1 * x3
+ - y1 * y1 * x2
+ )
+ / (y1 * x3 - y1 * x2 - y2 * x3 - y3 * x1 + y3 * x2 + y2 * x1)
+ )
return [Xs, Ys]
-#def arcCenter2(x1, y1, x2, y2, angle):
+
+# def arcCenter2(x1, y1, x2, y2, angle):
# # point M - center point between p1 and p2
# Mx = (x1 + x2) / 2.
# My = (y1 + y2) / 2.
-#
+#
# # p1_M - distance between point p1 and M
# p1_M = sqrt((x1 - Mx) ** 2 + (y1 - My) ** 2)
# radius = float("%4.9f" % abs(p1_M / sin(radians(angle / 2.)))) # radius of searching circle - line C_p1
# CenterDist = float("%4.9f" % abs(radius * cos(radians(angle / 2.)))) # radius of searching circle - line C_p1
-#
+#
# return CenterDist
+
def arcRadius(x1, y1, x2, y2, angle):
- #dx = abs(x2 - x1)
- #dy = abs(y2 - y1)
- #d = sqrt(dx ** 2 + dy ** 2) # distance between p1 and p2
+ # dx = abs(x2 - x1)
+ # dy = abs(y2 - y1)
+ # d = sqrt(dx ** 2 + dy ** 2) # distance between p1 and p2
# point M - center point between p1 and p2
- Mx = (x1 + x2) / 2.
- My = (y1 + y2) / 2.
-
+ Mx = (x1 + x2) / 2.0
+ My = (y1 + y2) / 2.0
+
# p1_M - distance between point p1 and M
p1_M = sqrt((x1 - Mx) ** 2 + (y1 - My) ** 2)
- radius = float("%4.9f" % abs(p1_M / sin(radians(angle / 2.)))) # radius of searching circle - line C_p1
-
- return radius
+ return float(f"{abs(p1_M / sin(radians(angle / 2.0))):4.9f}") # radius of searching circle - line C_p1
+
-def arcAngles2 (edge,angle): #(xs, ys, xe, ye, cx, cy, angle):
+def arcAngles2(edge, angle): # (xs, ys, xe, ye, cx, cy, angle):
- #sa = atan2 (ys-cy, xs-cx)
- #ea = atan2 (ye-cy, xe-cx)
+ # sa = atan2 (ys-cy, xs-cx)
+ # ea = atan2 (ye-cy, xe-cx)
##if angle > 0:
## sa = atan2 (ys-cy, xs-cx)
## ea = sa + radians(angle) #2*pi+angle #atan2 (ye-cy, xe-cx)
##else:
## sa = atan2 (ye-cy, xe-cx)
## ea = sa + radians(abs(angle)) # 2*pi+angle #atan2 (ye-cy, xe-cx)
- #ea = ea - pi/2
- #sa = sa - pi/2
- #if ea == sa:
+ # ea = ea - pi/2
+ # sa = sa - pi/2
+ # if ea == sa:
# ea = pi/2
-
+
if DraftGeomUtils.geomType(edge) == "Circle":
- Radius = edge.Curve.Radius
placement = FreeCAD.Placement(edge.Placement)
- #delta = edge.Curve.Center.sub(placement.Base)
- #placement.move(delta)
+ # delta = edge.Curve.Center.sub(placement.Base)
+ # placement.move(delta)
if len(edge.Vertexes) > 1:
- ref = placement.multVec(FreeCAD.Vector(1,0,0))
+ ref = placement.multVec(FreeCAD.Vector(1, 0, 0))
v1 = (edge.Vertexes[0].Point).sub(edge.Curve.Center)
v2 = (edge.Vertexes[-1].Point).sub(edge.Curve.Center)
- a1 = -(DraftVecUtils.angle(v1,ref))
- a2 = -(DraftVecUtils.angle(v2,ref))
- FirstAngle = a1
- LastAngle = a2
- if angle <0:
+ a1 = -(DraftVecUtils.angle(v1, ref))
+ a2 = -(DraftVecUtils.angle(v2, ref))
+ if angle < 0:
return [a2, a1]
- else:
- return [a1, a2]
-
+ return [a1, a2]
+
+
def arcAngles(x1, y1, x2, y2, Cx, Cy, angle):
if angle > 0:
startAngle = atan2(y1 - Cy, x1 - Cx)
- if startAngle < 0.:
+ if startAngle < 0.0:
startAngle = 6.28 + startAngle
-
+
stopAngle = startAngle + radians(angle) # STOP ANGLE
else:
startAngle = atan2(y2 - Cy, x2 - Cx)
- if startAngle < 0.:
+ if startAngle < 0.0:
startAngle = 6.28 + startAngle
stopAngle = startAngle + radians(abs(angle)) # STOP ANGLE
- #
- startAngle = float("%4.2f" % startAngle) - pi/2
- stopAngle = float("%4.2f" % stopAngle) - pi/2
-
+ startAngle = float(f"{startAngle:4.2f}") - pi / 2
+ stopAngle = float(f"{stopAngle:4.2f}") - pi / 2
+
return [startAngle, stopAngle]
+
def shiftPointOnLine(x1, y1, x2, y2, distance):
if x2 - x1 == 0: # vertical line
x_T1 = x1
@@ -8722,24 +9431,29 @@ def shiftPointOnLine(x1, y1, x2, y2, distance):
y_T1 = y1
else:
alfa = atan(a)
- #alfa = tan(a)
+ # alfa = tan(a)
x_T1 = x1 - distance * cos(alfa)
y_T1 = y1 - distance * sin(alfa)
return [x_T1, y_T1]
+
###
def getLine(layer, content, oType):
- layer=layer.replace('"','')
+ layer = layer.replace('"', "")
data = []
- source = ''.join(content)
- source=source.replace('"','')
+ source = "".join(content)
+ source = source.replace('"', "")
#
- #data1 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)(\s+\(angle\s+[0-9\.-]*?\)\s+|\s+)\(layer\s+{0}\)\s+\(width\s+([0-9\.]*?)\)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
- data1 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)(\s+\(angle\s+[0-9\.-]*?\)\s+|\s+)\(layer\s+{0}\)\s+\(width\s+([0-9\.]*?)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
- #TBD fp_line kv7
- #say(data1)
+ # data1 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)(\s+\(angle\s+[0-9\.-]*?\)\s+|\s+)\(layer\s+{0}\)\s+\(width\s+([0-9\.]*?)\)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
+ data1 = re.findall(
+ rf"\({oType}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)(\s+\(angle\s+[0-9\.-]*?\)\s+|\s+)\(layer\s+{layer}\)\s+\(width\s+([0-9\.]*?)\)",
+ source,
+ re.MULTILINE | re.DOTALL,
+ )
+ # TBD fp_line kv7
+ # say(data1)
for i in data1:
x1 = float(i[0])
y1 = float(i[1]) * (-1)
@@ -8748,17 +9462,21 @@ def getLine(layer, content, oType):
width = float(i[5])
data.append([x1, y1, x2, y2, width])
- #
return data
+
###
-def getLineF(layer, content, oType, m=[0,0]):
+def getLineF(layer, content, oType, m=[0, 0]):
data = []
- source = ''.join(content)
+ source = "".join(content)
#
- #data1 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)(\s+\(angle\s+[0-9\.-]*?\)\s+|\s+)\(layer\s+{0}\)\s+\(width\s+([0-9\.]*?)\)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
- data1 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)(\s+\(angle\s+[0-9\.-]*?\)\s+|\s+)\(layer\s+{0}\)\s+\(width\s+([0-9\.]*?)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
- #say(data1)
+ # data1 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)(\s+\(angle\s+[0-9\.-]*?\)\s+|\s+)\(layer\s+{0}\)\s+\(width\s+([0-9\.]*?)\)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
+ data1 = re.findall(
+ rf"\({oType}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)(\s+\(angle\s+[0-9\.-]*?\)\s+|\s+)\(layer\s+{layer}\)\s+\(width\s+([0-9\.]*?)\)",
+ source,
+ re.MULTILINE | re.DOTALL,
+ )
+ # say(data1)
for i in data1:
x1 = float(i[0])
y1 = float(i[1]) * (-1)
@@ -8766,7 +9484,7 @@ def getLineF(layer, content, oType, m=[0,0]):
y2 = float(i[3]) * (-1)
width = float(i[5])
if [x1, y1] == [x2, y2]:
- continue
+ continue
if m[0] != 0:
x1 += m[0]
x2 += m[0]
@@ -8775,19 +9493,22 @@ def getLineF(layer, content, oType, m=[0,0]):
y2 += m[1]
data.append([x1, y1, x2, y2, width])
- #
return data
+
def getCircle(layer, content, oType):
data = []
- #
- source = ''.join(content)
- layer=layer.replace('"','')
- source=source.replace('"','')
- #data1 = re.findall(r'\({1}\s+\(center\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)(\s+\(width\s+([0-9\.]*?)\)|)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
- data1 = re.findall(r'\({1}\s+\(center\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)(\s+\(width\s+([0-9\.]*?)\)|)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
- #say(source)
- #say(data1)
+ source = "".join(content)
+ layer = layer.replace('"', "")
+ source = source.replace('"', "")
+ # data1 = re.findall(r'\({1}\s+\(center\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)(\s+\(width\s+([0-9\.]*?)\)|)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
+ data1 = re.findall(
+ rf"\({oType}\s+\(center\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(layer\s+{layer}\)(\s+\(width\s+([0-9\.]*?)\)|)",
+ source,
+ re.MULTILINE | re.DOTALL,
+ )
+ # say(source)
+ # say(data1)
for i in data1:
xs = float(i[0])
ys = float(i[1]) * (-1)
@@ -8796,24 +9517,26 @@ def getCircle(layer, content, oType):
radius = sqrt((xs - x1) ** 2 + (ys - y1) ** 2)
- if i[5] == '':
- width = 0.01
- else:
- width = float(i[5])
+ width = 0.01 if i[5] == "" else float(i[5])
data.append([xs, ys, radius, width])
#
- #say(data)
+ # say(data)
return data
+
+
###
-def getCircleF(layer, content, oType, m=[0,0]):
+def getCircleF(layer, content, oType, m=[0, 0]):
data = []
- #
- source = ''.join(content)
- #data1 = re.findall(r'\({1}\s+\(center\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)(\s+\(width\s+([0-9\.]*?)\)|)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
- data1 = re.findall(r'\({1}\s+\(center\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)(\s+\(width\s+([0-9\.]*?)\)|)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
- #say(source)
- #say(data1)
+ source = "".join(content)
+ # data1 = re.findall(r'\({1}\s+\(center\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)(\s+\(width\s+([0-9\.]*?)\)|)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
+ data1 = re.findall(
+ rf"\({oType}\s+\(center\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(layer\s+{layer}\)(\s+\(width\s+([0-9\.]*?)\)|)",
+ source,
+ re.MULTILINE | re.DOTALL,
+ )
+ # say(source)
+ # say(data1)
for i in data1:
xs = float(i[0])
ys = float(i[1]) * (-1)
@@ -8822,10 +9545,7 @@ def getCircleF(layer, content, oType, m=[0,0]):
radius = sqrt((xs - x1) ** 2 + (ys - y1) ** 2)
- if i[5] == '':
- width = 0.01
- else:
- width = float(i[5])
+ width = 0.01 if i[5] == "" else float(i[5])
if m[0] != 0:
xs += m[0]
if m[1] != 0:
@@ -8833,8 +9553,10 @@ def getCircleF(layer, content, oType, m=[0,0]):
data.append([xs, ys, radius, width])
#
- #say(data)
+ # say(data)
return data
+
+
###
def rotPoint(point, ref, angle):
sinKAT = self.sinus(angle)
@@ -8844,6 +9566,7 @@ def rotPoint(point, ref, angle):
y1R = (point[0] * sinKAT) + (point[1] * cosKAT) + ref[1]
return [x1R, y1R]
+
###
def rotPoint2(point, ref, angle):
sinKAT = sinus(angle)
@@ -8851,34 +9574,41 @@ def rotPoint2(point, ref, angle):
x1R = ((point[0] - ref[0]) * cosKAT) - sinKAT * (point[1] - ref[1]) + ref[0]
y1R = ((point[0] - ref[0]) * sinKAT) + cosKAT * (point[1] - ref[1]) + ref[1]
return [x1R, y1R]
+
+
###
def getArc(layer, content, oType):
data = []
- source = ''.join(content)
- source = source.replace('"','')
- layer = layer.replace('"','')
- #data1 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(angle\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)(\s+\(width\s+([0-9\.]*?)\)|)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
- #(fp_arc (start 0.015 -0.03) (end 22.348 -2.772) (angle -17) (layer Edge.Cuts) (width 0.16))
- data1 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(angle\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)(\s+\(width\s+([0-9\.]*?)|)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
+ source = "".join(content)
+ source = source.replace('"', "")
+ layer = layer.replace('"', "")
+ # data1 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(angle\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)(\s+\(width\s+([0-9\.]*?)\)|)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
+ # (fp_arc (start 0.015 -0.03) (end 22.348 -2.772) (angle -17) (layer Edge.Cuts) (width 0.16))
+ data1 = re.findall(
+ rf"\({oType}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(angle\s+([0-9\.-]*?)\)\s+\(layer\s+{layer}\)(\s+\(width\s+([0-9\.]*?)|)\)",
+ source,
+ re.MULTILINE | re.DOTALL,
+ )
for i in data1:
xs = float(i[0])
ys = float(i[1])
x1 = float(i[2])
y1 = float(i[3])
curve = float(i[4])
- if i[6].strip() != '':
- width = float(i[6])
- else:
- width = 0
- if abs(curve)==360:
+ width = float(i[6]) if i[6].strip() != "" else 0
+ if abs(curve) == 360:
[x2, y2] = [xs, ys]
else:
[x2, y2] = rotPoint2([x1, y1], [xs, ys], curve)
data.append([x1, y1 * (-1), x2, y2 * (-1), curve, width])
- if len (data) == 0:
+ if len(data) == 0:
# (fp_arc (start 20.570471 -9.181725) (mid 21.697398 -6.042909) (end 22.348 -2.772) (layer "Edge.Cuts") (width 0.16) (tstamp 30b75c25-1d2c-45e7-83e2-bb3be98f8f83))
- data2 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(mid\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)\s+\(width\s+([0-9\.]*?)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
- #print(data2,data,data1)
+ data2 = re.findall(
+ rf"\({oType}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(mid\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(layer\s+{layer}\)\s+\(width\s+([0-9\.]*?)\)",
+ source,
+ re.MULTILINE | re.DOTALL,
+ )
+ # print(data2,data,data1)
for i in data2:
xs = float(i[0])
ys = float(i[1])
@@ -8886,31 +9616,28 @@ def getArc(layer, content, oType):
ym = float(i[3])
x1 = float(i[4])
y1 = float(i[5])
- if i[6].strip() != '':
- width = float(i[6])
- else:
- width = 0
+ width = float(i[6]) if i[6].strip() != "" else 0
data.append([xs, ys * (-1), xm, ym * (-1), x1, y1 * (-1), width])
- #
return data
+
###
-def getArcF(layer, content, oType, m=[0,0]):
+def getArcF(layer, content, oType, m=[0, 0]):
data = []
- #
- source = ''.join(content)
- #data1 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(angle\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)(\s+\(width\s+([0-9\.]*?)\)|)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
- data1 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(angle\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)(\s+\(width\s+([0-9\.]*?)|)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
+ source = "".join(content)
+ # data1 = re.findall(r'\({1}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(angle\s+([0-9\.-]*?)\)\s+\(layer\s+{0}\)(\s+\(width\s+([0-9\.]*?)\)|)\)'.format(layer, oType), source, re.MULTILINE|re.DOTALL)
+ data1 = re.findall(
+ rf"\({oType}\s+\(start\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(end\s+([0-9\.-]*?)\s+([0-9\.-]*?)\)\s+\(angle\s+([0-9\.-]*?)\)\s+\(layer\s+{layer}\)(\s+\(width\s+([0-9\.]*?)|)\)",
+ source,
+ re.MULTILINE | re.DOTALL,
+ )
for i in data1:
xs = float(i[0])
ys = float(i[1])
x1 = float(i[2])
y1 = float(i[3])
curve = float(i[4])
- if i[6].strip() != '':
- width = float(i[6])
- else:
- width = 0
+ width = float(i[6]) if i[6].strip() != "" else 0
[x2, y2] = rotPoint2([x1, y1], [xs, ys], curve)
y1 *= -1
@@ -8922,82 +9649,83 @@ def getArcF(layer, content, oType, m=[0,0]):
y1 += m[1]
y2 += m[1]
- data.append([x1, y1 , x2, y2, curve, width])
- #data.append([x1, y1 * (-1), x2, y2 * (-1), curve, width])
- #
+ data.append([x1, y1, x2, y2, curve, width])
+ # data.append([x1, y1 * (-1), x2, y2 * (-1), curve, width])
return data
+
def getModName(source):
- #say("here test0")
- #for x in source:
+ # say("here test0")
+ # for x in source:
# x.encode('utf-8')
# say(x)
- #say("here test1")
- #model = ''.join(u)
- model = ''.join(source)
- #sayw("here")#;
- #sayw("here test2")
- match = re.search(r'((\(module\s)|(\(footprint\s))+(.+?)\(layer', model, re.MULTILINE|re.DOTALL)
+ # say("here test1")
+ # model = ''.join(u)
+ model = "".join(source)
+ # sayw("here")#;
+ # sayw("here test2")
+ match = re.search(r"((\(module\s)|(\(footprint\s))+(.+?)\(layer", model, re.MULTILINE | re.DOTALL)
if match is not None:
model_name = match.groups(0)[3]
- if ' (version' in model_name:
- model_name = model_name[:model_name.index(' (version')]
- model_name = model_name.replace('"','').rstrip()+'-'
-
+ if " (version" in model_name:
+ model_name = model_name[: model_name.index(" (version")]
+ model_name = model_name.replace('"', "").rstrip() + "-"
+
return model_name
+
+
###
def getwrlData(source):
- model = ''.join(source)
- wrl_pos=['0', '0', '0']
- if re.search(r'\(at\s+\(xyz+\s(.+?)\)', model, re.MULTILINE|re.DOTALL) is not None:
- pos_vrml = re.search(r'\(at\s+\(xyz+\s(.+?)\)', model, re.MULTILINE|re.DOTALL).groups(0)[0]
- #pos_vrml=pos_vrml[5:]
- wrl_pos=pos_vrml.split(" ")
- xp_vrml=wrl_pos[0]
- #say('alive')
- yp_vrml=wrl_pos[1]
- zp_vrml=wrl_pos[2]
- #say(wrl_pos);
- #wrl_pos=(xp_vrml,yp_vrml,zp_vrml)
- #say(wrl_pos);
- #
- if re.search(r'\(offset\s+\(xyz+\s(.+?)\)', model, re.MULTILINE|re.DOTALL) is not None:
- pos_vrml = re.search(r'\(offset\s+\(xyz+\s(.+?)\)', model, re.MULTILINE|re.DOTALL).groups(0)[0]
- #pos_vrml=pos_vrml[5:]
- wrl_pos=pos_vrml.split(" ")
- xp_vrml=wrl_pos[0]
- #say('alive')
- yp_vrml=wrl_pos[1]
- zp_vrml=wrl_pos[2]
- #say(wrl_pos);
- #wrl_pos=(xp_vrml,yp_vrml,zp_vrml)
+ model = "".join(source)
+ wrl_pos = ["0", "0", "0"]
+ if re.search(r"\(at\s+\(xyz+\s(.+?)\)", model, re.MULTILINE | re.DOTALL) is not None:
+ pos_vrml = re.search(r"\(at\s+\(xyz+\s(.+?)\)", model, re.MULTILINE | re.DOTALL).groups(0)[0]
+ # pos_vrml=pos_vrml[5:]
+ wrl_pos = pos_vrml.split(" ")
+ wrl_pos[0]
+ # say('alive')
+ wrl_pos[1]
+ wrl_pos[2]
+ # say(wrl_pos);
+ # wrl_pos=(xp_vrml,yp_vrml,zp_vrml)
+ # say(wrl_pos);
#
- scale_vrml=['1', '1', '1']
- if re.search(r'\(scale\s+(.+?)\)', model, re.MULTILINE|re.DOTALL) is not None:
- sc_vrml = re.search(r'\(scale\s+(.+?)\)', model, re.MULTILINE|re.DOTALL).groups(0)[0]
- sc_vrml=sc_vrml[5:]
- scale_vrml=sc_vrml.split(" ")
- xsc_vrml=scale_vrml[0]
- ysc_vrml=scale_vrml[1]
- zsc_vrml=scale_vrml[2]
- #say(scale_vrml);
- #say(scale_vrml);
+ if re.search(r"\(offset\s+\(xyz+\s(.+?)\)", model, re.MULTILINE | re.DOTALL) is not None:
+ pos_vrml = re.search(r"\(offset\s+\(xyz+\s(.+?)\)", model, re.MULTILINE | re.DOTALL).groups(0)[0]
+ # pos_vrml=pos_vrml[5:]
+ wrl_pos = pos_vrml.split(" ")
+ wrl_pos[0]
+ # say('alive')
+ wrl_pos[1]
+ wrl_pos[2]
+ # say(wrl_pos);
+ # wrl_pos=(xp_vrml,yp_vrml,zp_vrml)
+ scale_vrml = ["1", "1", "1"]
+ if re.search(r"\(scale\s+(.+?)\)", model, re.MULTILINE | re.DOTALL) is not None:
+ sc_vrml = re.search(r"\(scale\s+(.+?)\)", model, re.MULTILINE | re.DOTALL).groups(0)[0]
+ sc_vrml = sc_vrml[5:]
+ scale_vrml = sc_vrml.split(" ")
+ scale_vrml[0]
+ scale_vrml[1]
+ scale_vrml[2]
+ # say(scale_vrml);
+ # say(scale_vrml);
#
- rot_wrl=['0', '0', '0']
- zrot_vrml=''
- if re.search(r'\(rotate\s+(.+?)\)', model, re.MULTILINE|re.DOTALL) is not None:
- rot_vrml = re.search(r'\(rotate\s+(.+?)\)', model, re.MULTILINE|re.DOTALL).groups(0)[0]
- rot_vrml=rot_vrml[5:]
- rot_wrl=rot_vrml.split(" ")
- xrot_vrml=rot_wrl[0]
- yrot_vrml=rot_wrl[1]
- zrot_vrml=rot_wrl[2]
- #say(rot_wrl);
+ rot_wrl = ["0", "0", "0"]
+ zrot_vrml = ""
+ if re.search(r"\(rotate\s+(.+?)\)", model, re.MULTILINE | re.DOTALL) is not None:
+ rot_vrml = re.search(r"\(rotate\s+(.+?)\)", model, re.MULTILINE | re.DOTALL).groups(0)[0]
+ rot_vrml = rot_vrml[5:]
+ rot_wrl = rot_vrml.split(" ")
+ rot_wrl[0]
+ rot_wrl[1]
+ zrot_vrml = rot_wrl[2]
+ # say(rot_wrl);
else:
- rotz_vrml=False
- #say("hereA")
- #if rotz_vrml:
+ pass
+ # say("hereA")
+ # if rotz_vrml:
# zrot_vrml=zrot_vrml
# #say("rotz:"+rotz)
# ##rotz=rotz[5:]
@@ -9006,120 +9734,114 @@ def getwrlData(source):
# #say("rotz temp:"+temp[2])
# ##rotz=temp[2]
# #say("rotate vrml: "+rotz)
- if zrot_vrml=='':
- zrot_vrml=0.0
- else:
- zrot_vrml=float(zrot_vrml)
- rot=zrot_vrml #adding vrml module z-rotation
- #say(rot_wrl);
+ zrot_vrml = 0.0 if zrot_vrml == "" else float(zrot_vrml)
+ # say(rot_wrl);
return wrl_pos, scale_vrml, rot_wrl
+
def getwrlRot(source):
- model = ''.join(source)
- if re.search(r'\(rotate\s+(.+?)\)', model, re.MULTILINE|re.DOTALL) is not None:
- rotz_vrml = re.search(r'\(rotate\s+(.+?)\)', model, re.MULTILINE|re.DOTALL).groups(0)[0]
+ model = "".join(source)
+ if re.search(r"\(rotate\s+(.+?)\)", model, re.MULTILINE | re.DOTALL) is not None:
+ rotz_vrml = re.search(r"\(rotate\s+(.+?)\)", model, re.MULTILINE | re.DOTALL).groups(0)[0]
else:
- rotz_vrml=False
- #say("hereA")
- rotz=''
+ rotz_vrml = False
+ # say("hereA")
+ rotz = ""
if rotz_vrml:
- rotz=rotz_vrml
- #say("rotz:"+rotz)
- rotz=rotz[5:]
- #say("rotz:"+rotz)
- temp=rotz.split(" ")
- #say("rotz temp:"+temp[2])
- rotz=temp[2]
- #say("rotate vrml: "+rotz)
- if rotz=='':
- rotz=0.0
- else:
- rotz=float(rotz)
- rot=rotz #adding vrml module z-rotation
- return rot
+ rotz = rotz_vrml
+ # say("rotz:"+rotz)
+ rotz = rotz[5:]
+ # say("rotz:"+rotz)
+ temp = rotz.split(" ")
+ # say("rotz temp:"+temp[2])
+ rotz = temp[2]
+ # say("rotate vrml: "+rotz)
+ return 0.0 if rotz == "" else float(rotz)
+
###
def getPadsList(content):
pads = []
- #
- model = ''.join(content)
- #model_name = re.search(r'\(module\s+(.+?)\(layer', model, re.MULTILINE|re.DOTALL).groups(0)[0]
- #say(model_name)
+ model = "".join(content)
+ # model_name = re.search(r'\(module\s+(.+?)\(layer', model, re.MULTILINE|re.DOTALL).groups(0)[0]
+ # say(model_name)
- found = re.findall(r'\(pad .*', model, re.MULTILINE|re.DOTALL)
- #found_fp = re.findall(r'\(fp_poly .*', model, re.MULTILINE|re.DOTALL)
- zones = re.findall(r'\(zone .*', model, re.MULTILINE|re.DOTALL)
+ found = re.findall(r"\(pad .*", model, re.MULTILINE | re.DOTALL)
+ # found_fp = re.findall(r'\(fp_poly .*', model, re.MULTILINE|re.DOTALL)
+ zones = re.findall(r"\(zone .*", model, re.MULTILINE | re.DOTALL)
if len(zones):
- zones = zones[0].strip().split('(zone ')
+ zones = zones[0].strip().split("(zone ")
## TBD create sketch for zones
- #print(zones)
- #for z in zones:
+ # print(zones)
+ # for z in zones:
# if z != '':
if len(found):
- found = found[0].strip().split('(pad ')
- #removing extra keepout zones
+ found = found[0].strip().split("(pad ")
+ # removing extra keepout zones
for count, p in enumerate(found):
- if '(zone ' in p:
- #print (len(p))
+ if "(zone " in p:
+ # print (len(p))
idx = p.index("(zone ")
z = p[0:idx]
found[count] = z
for j in found:
- if j != '':
- [x, y, rot] = re.search(r'\(at\s+([0-9\.-]*?)\s+([0-9\.-]*?)(\s+[0-9\.-]*?|)\)', j).groups()
- pType= re.search(r'^.*?\s+([a-zA-Z_]+?)\s+', j).groups(0)[0] # pad type - SMD/thru_hole/connect
- pShape = re.search(r'^.+?\s+.+?\s+([a-zA-Z_]+?)\s+', j).groups(0)[0] # pad shape - circle/rec/oval/trapezoid/roundrect
- pRoundG = re.search(r'\(roundrect_rratio\s+([0-9\.-]+?)\)', j)
- if pRoundG is not None:
- pRound = pRoundG.groups(0)[0]
- else:
- pRound=None
- #pCircleG = re.search(r'\(gr_circle+.+?\)\)', j, re.MULTILINE|re.DOTALL) #re.search(r'\(gr_circle\s.+(?=\)\)$)', j) #(?<=^startstr).+(?=stopstr$)
- pCircleG = re.search(r'(\(gr_circle)\s+(.+?)\)\)', j) #, re.MULTILINE|re.DOTALL) #re.search(r'\(gr_circle\s.+(?=\)\)$)', j) #(?<=^startstr).+(?=stopstr$)
- #print(pCircleG);print(j);stop
+ if j != "":
+ [x, y, rot] = re.search(r"\(at\s+([0-9\.-]*?)\s+([0-9\.-]*?)(\s+[0-9\.-]*?|)\)", j).groups()
+ pType = re.search(r"^.*?\s+([a-zA-Z_]+?)\s+", j).groups(0)[0] # pad type - SMD/thru_hole/connect
+ pShape = re.search(r"^.+?\s+.+?\s+([a-zA-Z_]+?)\s+", j).groups(0)[
+ 0
+ ] # pad shape - circle/rec/oval/trapezoid/roundrect
+ pRoundG = re.search(r"\(roundrect_rratio\s+([0-9\.-]+?)\)", j)
+ pRound = pRoundG.groups(0)[0] if pRoundG is not None else None
+ # pCircleG = re.search(r'\(gr_circle+.+?\)\)', j, re.MULTILINE|re.DOTALL) #re.search(r'\(gr_circle\s.+(?=\)\)$)', j) #(?<=^startstr).+(?=stopstr$)
+ pCircleG = re.search(
+ r"(\(gr_circle)\s+(.+?)\)\)",
+ j,
+ ) # , re.MULTILINE|re.DOTALL) #re.search(r'\(gr_circle\s.+(?=\)\)$)', j) #(?<=^startstr).+(?=stopstr$)
+ # print(pCircleG);print(j);stop
if pCircleG is not None:
- pCircleG = pCircleG.groups(0)[1].split(')')
- pCircleG[1]=pCircleG[1].lstrip(' ')
- pCircleG[2]=pCircleG[2].lstrip(' ')
- #say(pCircleG);stop
+ pCircleG = pCircleG.groups(0)[1].split(")")
+ pCircleG[1] = pCircleG[1].lstrip(" ")
+ pCircleG[2] = pCircleG[2].lstrip(" ")
+ # say(pCircleG);stop
else:
- pCircleG=None
- #sayw(pShape)
- #sayw(pRound)
- [dx, dy] = re.search(r'\(size\s+([0-9\.-]+?)\s+([0-9\.-]+?)\)', j).groups(0) #
+ pCircleG = None
+ # sayw(pShape)
+ # sayw(pRound)
+ [dx, dy] = re.search(r"\(size\s+([0-9\.-]+?)\s+([0-9\.-]+?)\)", j).groups(0)
try:
- layers = re.search(r'\(layers\s+(.+?)\)', j).groups(0)[0] #
+ layers = re.search(r"\(layers\s+(.+?)\)", j).groups(0)[0]
except:
- layers = 'F.SilkS'
- #layers = None
- sayerr('NO LAYERS on PAD') #test utf-8 test pads
+ layers = "F.SilkS"
+ # layers = None
+ sayerr("NO LAYERS on PAD") # test utf-8 test pads
# print(layers)
# stop
- data = re.search(r'\(drill(\s+oval\s+|\s+)(.*?)(\s+[-0-9\.]*?|)(\s+\(offset\s+(.*?)\s+(.*?)\)|)\)', j)
- data_off = re.search(r'\(offset\s+([0-9\.-]+?)\s+([0-9\.-]+?)\)', j)
- pnts = re.search(r'\(gr_poly\s\(pts(.*?)\)\s\(width', j, re.MULTILINE|re.DOTALL)
- #pnts_nt = re.search(r'\(fp_poly\s\(pts(.*?)\)\s\(width', j, re.MULTILINE|re.DOTALL)
- #if pnts_nt is not None:
+ data = re.search(r"\(drill(\s+oval\s+|\s+)(.*?)(\s+[-0-9\.]*?|)(\s+\(offset\s+(.*?)\s+(.*?)\)|)\)", j)
+ data_off = re.search(r"\(offset\s+([0-9\.-]+?)\s+([0-9\.-]+?)\)", j)
+ pnts = re.search(r"\(gr_poly\s\(pts(.*?)\)\s\(width", j, re.MULTILINE | re.DOTALL)
+ # pnts_nt = re.search(r'\(fp_poly\s\(pts(.*?)\)\s\(width', j, re.MULTILINE|re.DOTALL)
+ # if pnts_nt is not None:
# pnts = pnts_nt #re.search(r'\(fp_poly\s\(pts(.*?)\)\s\(width', j, re.MULTILINE|re.DOTALL)
# pShape = 'NetTie'
- anchor = re.search(r'\(anchor\s(.*?)\)\)', j)
+ anchor = re.search(r"\(anchor\s(.*?)\)\)", j)
if anchor is not None:
- anchor=anchor.groups()[0]
- #print anchor
- #if pnts is not None:
+ anchor = anchor.groups()[0]
+ # print anchor
+ # if pnts is not None:
# print pnts.groups(0)[0].split('(xy')
#
x = float(x)
y = float(y) * (-1)
dx = float(dx)
dy = float(dy)
- if rot == '' or len(rot.strip(' '))==0:
+ if rot == "" or len(rot.strip(" ")) == 0:
rot = 0.0
else:
- #print rot
+ # print rot
rot = float(rot)
- #print(pType)
- if pType == 'smd' or pType == 'connect' or data is None:
+ # print(pType)
+ if pType in {"smd", "connect"} or data is None:
drill_x = 0.0
drill_y = 0.0
hType = None
@@ -9127,96 +9849,110 @@ def getPadsList(content):
[xOF, yOF] = [0.0, 0.0]
else:
data_off = data_off.groups()
- if not data_off[0] or data_off[0].strip() == '':
- xOF = 0.0
- else:
- xOF = float(data_off[0])
+ xOF = 0.0 if not data_off[0] or data_off[0].strip() == "" else float(data_off[0])
- if not data_off[1] or data_off[1].strip() == '':
- yOF = 0.0
- else:
- yOF = float(data_off[1])
+ yOF = 0.0 if not data_off[1] or data_off[1].strip() == "" else float(data_off[1])
else:
data = data.groups()
hType = data[0]
- if hType.strip() == '':
- hType = 'circle'
+ if hType.strip() == "":
+ hType = "circle"
- drill_x = float(data[1]) #/ 2.0
- if not data[2] or data[2].strip() == '':
- drill_y=drill_x
+ drill_x = float(data[1]) # / 2.0
+ if not data[2] or data[2].strip() == "":
+ drill_y = drill_x
else:
- drill_y = float(data[2]) #/ 2.0
- #drill_y=drill_x
+ drill_y = float(data[2]) # / 2.0
+ # drill_y=drill_x
- if not data[4] or data[4].strip() == '':
- xOF = 0.0
- else:
- xOF = float(data[4])
+ xOF = 0.0 if not data[4] or data[4].strip() == "" else float(data[4])
- if not data[5] or data[5].strip() == '':
- yOF = 0.0
- else:
- yOF = float(data[5])
+ yOF = 0.0 if not data[5] or data[5].strip() == "" else float(data[5])
##
- #say(data)
- pads.append({'x': x, 'y': y, 'rot': rot, 'padType': pType, 'padShape': pShape, 'rx': drill_x, 'ry': drill_y, 'dx': dx, 'dy': dy, \
- 'holeType': hType, 'xOF': xOF, 'yOF': yOF, 'layers': layers, 'points': pnts, 'anchor': anchor, 'rratio': pRound, 'geomC':pCircleG})
-
- #say(pads)
+ # say(data)
+ pads.append(
+ {
+ "x": x,
+ "y": y,
+ "rot": rot,
+ "padType": pType,
+ "padShape": pShape,
+ "rx": drill_x,
+ "ry": drill_y,
+ "dx": dx,
+ "dy": dy,
+ "holeType": hType,
+ "xOF": xOF,
+ "yOF": yOF,
+ "layers": layers,
+ "points": pnts,
+ "anchor": anchor,
+ "rratio": pRound,
+ "geomC": pCircleG,
+ },
+ )
+
+ # say(pads)
#
return pads
+
+
###
###
def getPolyList(content):
- pads = []
- #
- model = ''.join(content)
- #model_name = re.search(r'\(module\s+(.+?)\(layer', model, re.MULTILINE|re.DOTALL).groups(0)[0]
- #say(model_name)
+ model = "".join(content)
+ # model_name = re.search(r'\(module\s+(.+?)\(layer', model, re.MULTILINE|re.DOTALL).groups(0)[0]
+ # say(model_name)
fp_pnts = []
width = 0.16
- found = re.findall(r'\(fp_poly.*', model, re.MULTILINE|re.DOTALL)
+ found = re.findall(r"\(fp_poly.*", model, re.MULTILINE | re.DOTALL)
if len(found):
- found = found[0].strip().split('(fp_poly ')
+ found = found[0].strip().split("(fp_poly ")
for j in found:
- #print('j',j)
- if j != '':
+ # print('j',j)
+ if j != "":
try:
- layers = re.search(r'\(layer\s+(.+?)\)', j).groups(0)[0] #
+ layers = re.search(r"\(layer\s+(.+?)\)", j).groups(0)[0]
except:
- layers = 'F.SilkS'
- #layers = None
- sayerr('NO LAYER on NetTie') #test utf-8 test pads
- #print(layers)
+ layers = "F.SilkS"
+ # layers = None
+ sayerr("NO LAYER on NetTie") # test utf-8 test pads
+ # print(layers)
# stop
- #pnts = re.search(r'\(fp_poly\s\(pts(.*?)\)\s\(width', j, re.MULTILINE|re.DOTALL)
- pnts = re.search(r'\(pts(.*?)(.*?)\(width', j, re.MULTILINE|re.DOTALL)
- #pnts_nt = re.search(r'\(fp_poly\s\(pts(.*?)\)\s\(width', j, re.MULTILINE|re.DOTALL)
- #if pnts_nt is not None:
+ # pnts = re.search(r'\(fp_poly\s\(pts(.*?)\)\s\(width', j, re.MULTILINE|re.DOTALL)
+ pnts = re.search(r"\(pts(.*?)(.*?)\(width", j, re.MULTILINE | re.DOTALL)
+ # pnts_nt = re.search(r'\(fp_poly\s\(pts(.*?)\)\s\(width', j, re.MULTILINE|re.DOTALL)
+ # if pnts_nt is not None:
# pnts = pnts_nt #re.search(r'\(fp_poly\s\(pts(.*?)\)\s\(width', j, re.MULTILINE|re.DOTALL)
# pShape = 'NetTie'
- #print('pnts',pnts.group())
- width = re.search(r'\(width(.*?)\)', j, re.MULTILINE|re.DOTALL)
- width = float(width[0].strip().split('(width ')[1].strip(')'))
- #print('width',width)
- fp_pnts.append({'layers': layers, 'points': pnts})
+ # print('pnts',pnts.group())
+ width = re.search(r"\(width(.*?)\)", j, re.MULTILINE | re.DOTALL)
+ width = float(width[0].strip().split("(width ")[1].strip(")"))
+ # print('width',width)
+ fp_pnts.append({"layers": layers, "points": pnts})
- #say(fp_pnts)
+ # say(fp_pnts)
#
return fp_pnts, width
+
+
###
+
def makePoint(self, x, y):
wir = []
wir.append(Part.Point(FreeCAD.Base.Vector(x, y, 0)))
- mainObj = Part.Shape(wir)
- return mainObj
+ return Part.Shape(wir)
+
+
###
def makeFace(mainObj):
return Part.Face(mainObj)
+
+
###
+
def cutHole(mainObj, hole):
if hole[2] > min_val:
hole = [Part.Circle(FreeCAD.Vector(hole[0], hole[1]), FreeCAD.Vector(0, 0, 1), hole[2]).toShape()]
@@ -9225,35 +9961,37 @@ def cutHole(mainObj, hole):
mainObj = mainObj.cut(hole)
return mainObj
+
+
###
def cutObj(mainObj, hole):
- mainObj = mainObj.cut(hole)
- return mainObj
+ return mainObj.cut(hole)
+
+
###
def createCircle(x, y, r, w=0):
if w > min_val:
- mainObj = Part.Wire([Part.Circle(FreeCAD.Vector(x, y), FreeCAD.Vector(0, 0, 1), r + w / 2.).toShape()])
+ mainObj = Part.Wire([Part.Circle(FreeCAD.Vector(x, y), FreeCAD.Vector(0, 0, 1), r + w / 2.0).toShape()])
mainObj = makeFace(mainObj)
- mainObj = cutHole(mainObj, [x, y, r - w / 2.])
+ return cutHole(mainObj, [x, y, r - w / 2.0])
- return mainObj
- else:
- mainObj = [Part.Circle(FreeCAD.Vector(x, y), FreeCAD.Vector(0, 0, 1), r).toShape()]
+ mainObj = [Part.Circle(FreeCAD.Vector(x, y), FreeCAD.Vector(0, 0, 1), r).toShape()]
+
+ return makeFace(Part.Wire(mainObj))
- return makeFace(Part.Wire(mainObj))
###
-def createArc_OLD(p1, p2, curve, width=0.02, cap='round'):
+def createArc_OLD(p1, p2, curve, width=0.02, cap="round"):
try:
wir = []
if width <= 0:
width = 0.02
- width /= 2.
+ width /= 2.0
[x3, y3] = arcMidPoint(p1, p2, curve)
[xs, ys] = arcCenter(p1[0], p1[1], p2[0], p2[1], x3, y3)
##
- #a = (ys - p1[1]) / (xs - p1[0])
+ # a = (ys - p1[1]) / (xs - p1[0])
[xT_1, yT_1] = shiftPointOnLine(p1[0], p1[1], xs, ys, width)
[xT_4, yT_4] = shiftPointOnLine(p1[0], p1[1], xs, ys, -width)
###
@@ -9264,18 +10002,30 @@ def createArc_OLD(p1, p2, curve, width=0.02, cap='round'):
wir = []
## outer arc
[xT_3, yT_3] = arcMidPoint([xT_1, yT_1], [xT_2, yT_2], curve)
- wir.append(Part.Arc(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_3, yT_3, 0), FreeCAD.Base.Vector(xT_2, yT_2, 0)))
+ wir.append(
+ Part.Arc(
+ FreeCAD.Base.Vector(xT_1, yT_1, 0),
+ FreeCAD.Base.Vector(xT_3, yT_3, 0),
+ FreeCAD.Base.Vector(xT_2, yT_2, 0),
+ ),
+ )
## inner arc
[xT_6, yT_6] = arcMidPoint([xT_4, yT_4], [xT_5, yT_5], curve)
- wir.append(Part.Arc(FreeCAD.Base.Vector(xT_4, yT_4, 0), FreeCAD.Base.Vector(xT_6, yT_6, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
+ wir.append(
+ Part.Arc(
+ FreeCAD.Base.Vector(xT_4, yT_4, 0),
+ FreeCAD.Base.Vector(xT_6, yT_6, 0),
+ FreeCAD.Base.Vector(xT_5, yT_5, 0),
+ ),
+ )
##
- if cap == 'flat':
+ if cap == "flat":
wir.append(PLine(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_4, yT_4, 0)))
wir.append(PLine(FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
else:
- #wir.append(PLine(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_4, yT_4, 0)))
- #wir.append(PLine(FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
- #start
+ # wir.append(PLine(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_4, yT_4, 0)))
+ # wir.append(PLine(FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
+ # start
if xs - p1[0] == 0: # vertical line
if curve > 0:
[xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
@@ -9289,36 +10039,37 @@ def createArc_OLD(p1, p2, curve, width=0.02, cap='round'):
[xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
else:
[xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
- pass
- else:
- #a = (ys - p1[1]) / (xs - p1[0])
- if curve > 0:
- if a > 0:
- if xT_1 > xs:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
- else:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
+ # a = (ys - p1[1]) / (xs - p1[0])
+ elif curve > 0:
+ if a > 0:
+ if xT_1 > xs:
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
else:
- if xT_1 > xs:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
- else:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
+ elif xT_1 > xs:
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
else:
- if a > 0:
- if xT_1 > xs:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
- else:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
- else:
- if xT_1 > xs:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
- else:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
+ elif a > 0:
+ if xT_1 > xs:
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
+ else:
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
+ elif xT_1 > xs:
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
+ else:
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
- wir.append(Part.Arc(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_7, yT_7, 0), FreeCAD.Base.Vector(xT_4, yT_4, 0)))
+ wir.append(
+ Part.Arc(
+ FreeCAD.Base.Vector(xT_1, yT_1, 0),
+ FreeCAD.Base.Vector(xT_7, yT_7, 0),
+ FreeCAD.Base.Vector(xT_4, yT_4, 0),
+ ),
+ )
- #end
- #b = (ys - p2[1]) / (xs - p2[0])
+ # end
+ # b = (ys - p2[1]) / (xs - p2[0])
if curve > 0:
if xT_2 > xs:
@@ -9326,24 +10077,27 @@ def createArc_OLD(p1, p2, curve, width=0.02, cap='round'):
[xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
else:
[xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
+ elif xT_2 >= xT_5:
+ [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
else:
- if xT_2 >= xT_5:
- [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
- else:
- [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
- else:
- if xT_2 > xs:
- if xT_2 >= xT_5:
- [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
- else:
- [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
+ [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
+ elif xT_2 > xs:
+ if xT_2 >= xT_5:
+ [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
else:
- if xT_2 >= xT_5:
- [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
- else:
- [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
+ [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
+ elif xT_2 >= xT_5:
+ [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
+ else:
+ [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
- wir.append(Part.Arc(FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_8, yT_8, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
+ wir.append(
+ Part.Arc(
+ FreeCAD.Base.Vector(xT_2, yT_2, 0),
+ FreeCAD.Base.Vector(xT_8, yT_8, 0),
+ FreeCAD.Base.Vector(xT_5, yT_5, 0),
+ ),
+ )
####
mainObj = Part.Shape(wir)
@@ -9351,22 +10105,23 @@ def createArc_OLD(p1, p2, curve, width=0.02, cap='round'):
return makeFace(mainObj)
except Exception as e:
- FreeCAD.Console.PrintWarning(u"{0}\n".format(e))
+ FreeCAD.Console.PrintWarning(f"{e}\n")
+
###
###
-def createArc(p1, p2, curve, width=0.02, cap='round'):
+def createArc(p1, p2, curve, width=0.02, cap="round"):
try:
- #wir = []
+ # wir = []
# create edges
edges = []
if width <= 0:
width = 0.02
- width /= 2.
+ width /= 2.0
[x3, y3] = arcMidPoint(p1, p2, curve)
[xs, ys] = arcCenter(p1[0], p1[1], p2[0], p2[1], x3, y3)
##
- #a = (ys - p1[1]) / (xs - p1[0])
+ # a = (ys - p1[1]) / (xs - p1[0])
[xT_1, yT_1] = shiftPointOnLine(p1[0], p1[1], xs, ys, width)
[xT_4, yT_4] = shiftPointOnLine(p1[0], p1[1], xs, ys, -width)
###
@@ -9374,25 +10129,40 @@ def createArc(p1, p2, curve, width=0.02, cap='round'):
[xT_5, yT_5] = rotPoint2([xT_4, yT_4], [xs, ys], curve)
########
########
- wir = []
## outer arc
[xT_3, yT_3] = arcMidPoint([xT_1, yT_1], [xT_2, yT_2], curve)
- edges.append(Part.Edge(Part.Arc(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_3, yT_3, 0), FreeCAD.Base.Vector(xT_2, yT_2, 0))))
- #wir.append(Part.Arc(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_3, yT_3, 0), FreeCAD.Base.Vector(xT_2, yT_2, 0)))
+ edges.append(
+ Part.Edge(
+ Part.Arc(
+ FreeCAD.Base.Vector(xT_1, yT_1, 0),
+ FreeCAD.Base.Vector(xT_3, yT_3, 0),
+ FreeCAD.Base.Vector(xT_2, yT_2, 0),
+ ),
+ ),
+ )
+ # wir.append(Part.Arc(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_3, yT_3, 0), FreeCAD.Base.Vector(xT_2, yT_2, 0)))
## inner arc
[xT_6, yT_6] = arcMidPoint([xT_4, yT_4], [xT_5, yT_5], curve)
- edges.append(Part.Edge(Part.Arc(FreeCAD.Base.Vector(xT_4, yT_4, 0), FreeCAD.Base.Vector(xT_6, yT_6, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0))))
- #wir.append(Part.Arc(FreeCAD.Base.Vector(xT_4, yT_4, 0), FreeCAD.Base.Vector(xT_6, yT_6, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
+ edges.append(
+ Part.Edge(
+ Part.Arc(
+ FreeCAD.Base.Vector(xT_4, yT_4, 0),
+ FreeCAD.Base.Vector(xT_6, yT_6, 0),
+ FreeCAD.Base.Vector(xT_5, yT_5, 0),
+ ),
+ ),
+ )
+ # wir.append(Part.Arc(FreeCAD.Base.Vector(xT_4, yT_4, 0), FreeCAD.Base.Vector(xT_6, yT_6, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
##
- if cap == 'flat':
+ if cap == "flat":
edges.append(Part.Edge(PLine(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_4, yT_4, 0))))
edges.append(Part.Edge(PLine(FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0))))
- #wir.append(PLine(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_4, yT_4, 0)))
- #wir.append(PLine(FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
+ # wir.append(PLine(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_4, yT_4, 0)))
+ # wir.append(PLine(FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
else:
- #wir.append(PLine(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_4, yT_4, 0)))
- #wir.append(PLine(FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
- #start
+ # wir.append(PLine(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_4, yT_4, 0)))
+ # wir.append(PLine(FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
+ # start
if xs - p1[0] == 0: # vertical line
if curve > 0:
[xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
@@ -9406,37 +10176,40 @@ def createArc(p1, p2, curve, width=0.02, cap='round'):
[xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
else:
[xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
- pass
- else:
- #a = (ys - p1[1]) / (xs - p1[0])
- if curve > 0:
- if a > 0:
- if xT_1 > xs:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
- else:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
+ # a = (ys - p1[1]) / (xs - p1[0])
+ elif curve > 0:
+ if a > 0:
+ if xT_1 > xs:
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
else:
- if xT_1 > xs:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
- else:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
+ elif xT_1 > xs:
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
else:
- if a > 0:
- if xT_1 > xs:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
- else:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
- else:
- if xT_1 > xs:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
- else:
- [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
+ elif a > 0:
+ if xT_1 > xs:
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
+ else:
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
+ elif xT_1 > xs:
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], -180)
+ else:
+ [xT_7, yT_7] = arcMidPoint([xT_1, yT_1], [xT_4, yT_4], 180)
- edges.append(Part.Edge(Part.Arc(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_7, yT_7, 0), FreeCAD.Base.Vector(xT_4, yT_4, 0))))
- #wir.append(Part.Arc(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_7, yT_7, 0), FreeCAD.Base.Vector(xT_4, yT_4, 0)))
+ edges.append(
+ Part.Edge(
+ Part.Arc(
+ FreeCAD.Base.Vector(xT_1, yT_1, 0),
+ FreeCAD.Base.Vector(xT_7, yT_7, 0),
+ FreeCAD.Base.Vector(xT_4, yT_4, 0),
+ ),
+ ),
+ )
+ # wir.append(Part.Arc(FreeCAD.Base.Vector(xT_1, yT_1, 0), FreeCAD.Base.Vector(xT_7, yT_7, 0), FreeCAD.Base.Vector(xT_4, yT_4, 0)))
- #end
- #b = (ys - p2[1]) / (xs - p2[0])
+ # end
+ # b = (ys - p2[1]) / (xs - p2[0])
if curve > 0:
if xT_2 > xs:
@@ -9444,25 +10217,30 @@ def createArc(p1, p2, curve, width=0.02, cap='round'):
[xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
else:
[xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
+ elif xT_2 >= xT_5:
+ [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
else:
- if xT_2 >= xT_5:
- [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
- else:
- [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
- else:
- if xT_2 > xs:
- if xT_2 >= xT_5:
- [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
- else:
- [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
+ [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
+ elif xT_2 > xs:
+ if xT_2 >= xT_5:
+ [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
else:
- if xT_2 >= xT_5:
- [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
- else:
- [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
-
- edges.append(Part.Edge(Part.Arc(FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_8, yT_8, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0))))
- #wir.append(Part.Arc(FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_8, yT_8, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
+ [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
+ elif xT_2 >= xT_5:
+ [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], 180)
+ else:
+ [xT_8, yT_8] = arcMidPoint([xT_2, yT_2], [xT_5, yT_5], -180)
+
+ edges.append(
+ Part.Edge(
+ Part.Arc(
+ FreeCAD.Base.Vector(xT_2, yT_2, 0),
+ FreeCAD.Base.Vector(xT_8, yT_8, 0),
+ FreeCAD.Base.Vector(xT_5, yT_5, 0),
+ ),
+ ),
+ )
+ # wir.append(Part.Arc(FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_8, yT_8, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0)))
####
sortedEdges = Part.__sortEdges__(edges)
@@ -9474,35 +10252,40 @@ def createArc(p1, p2, curve, width=0.02, cap='round'):
# return makeFace(mainObj)
except Exception as e:
- FreeCAD.Console.PrintWarning(u"{0}\n".format(e))
+ FreeCAD.Console.PrintWarning(f"{e}\n")
+
###
+
###
-def addArc_3(p1, p2, curve, width=0, cap='round'):
- #print curve, ' arc angle'
+def addArc_3(p1, p2, curve, width=0, cap="round"):
+ # print curve, ' arc angle'
if abs(curve) == 360:
- #print p1
- #print p2
+ # print p1
+ # print p2
r = sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2)
- #print r
+ # print r
return createCircle(p1[0], p1[1], r, width)
- else:
- return createArc(p1, p2, curve, width, cap)
+ return createArc(p1, p2, curve, width, cap)
+
###
def addLine_2(x1, y1, x2, y2, width=0.01):
if x1 == x2 and y1 == y2:
return makePoint(x1, y1, 0)
- else:
- return createLine(x1, y1, x2, y2, width)
+ return createLine(x1, y1, x2, y2, width)
+
+
###
def addCircle_2(x, y, r, w=0):
return createCircle(x, y, r, w)
+
+
###
def createLine(x1, y1, x2, y2, width=0.01):
- #say("create line routine")
- z_silk_offset=0.01
+ # say("create line routine")
+ z_silk_offset = 0.01
if width <= 0:
width = 0.01
@@ -9510,80 +10293,92 @@ def createLine(x1, y1, x2, y2, width=0.01):
length = sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
# angle of inclination
- if x1 > x2:
- iang = degrees(atan2(y1 - y2, x1 - x2)) - 90
- else:
- iang = degrees(atan2(y2 - y1, x2 - x1)) - 90
+ iang = degrees(atan2(y1 - y2, x1 - x2)) - 90 if x1 > x2 else degrees(atan2(y2 - y1, x2 - x1)) - 90
if x1 > x2:
iang += 180
# radius of curvature at both ends of the path
- r = width / 2.
+ r = width / 2.0
# create edges
edges = []
edges.append(Part.Edge(PLine(FreeCAD.Base.Vector(0 - r, 0, 0), FreeCAD.Base.Vector(0 - r, length, 0))))
edges.append(Part.Edge(PLine(FreeCAD.Base.Vector(0 + r, 0, 0), FreeCAD.Base.Vector(0 + r, length, 0))))
-
+
# create wire
- #wir = []
- #wir.append(PLine(FreeCAD.Base.Vector(0 - r, 0, 0), FreeCAD.Base.Vector(0 - r, length, 0)))
- #wir.append(PLine(FreeCAD.Base.Vector(0 + r, 0, 0), FreeCAD.Base.Vector(0 + r, length, 0)))
+ # wir = []
+ # wir.append(PLine(FreeCAD.Base.Vector(0 - r, 0, 0), FreeCAD.Base.Vector(0 - r, length, 0)))
+ # wir.append(PLine(FreeCAD.Base.Vector(0 + r, 0, 0), FreeCAD.Base.Vector(0 + r, length, 0)))
p1 = [0 - r, 0]
p2 = [0, 0 - r]
p3 = [0 + r, 0]
- edges.append(Part.Edge(Part.Arc(FreeCAD.Base.Vector(p1[0], p1[1], 0), FreeCAD.Base.Vector(p2[0], p2[1], 0), FreeCAD.Base.Vector(p3[0], p3[1], 0))))
- #wir.append(Part.Arc(FreeCAD.Base.Vector(p1[0], p1[1], 0), FreeCAD.Base.Vector(p2[0], p2[1], 0), FreeCAD.Base.Vector(p3[0], p3[1], 0)))
+ edges.append(
+ Part.Edge(
+ Part.Arc(
+ FreeCAD.Base.Vector(p1[0], p1[1], 0),
+ FreeCAD.Base.Vector(p2[0], p2[1], 0),
+ FreeCAD.Base.Vector(p3[0], p3[1], 0),
+ ),
+ ),
+ )
+ # wir.append(Part.Arc(FreeCAD.Base.Vector(p1[0], p1[1], 0), FreeCAD.Base.Vector(p2[0], p2[1], 0), FreeCAD.Base.Vector(p3[0], p3[1], 0)))
p1 = [0 - r, length]
p2 = [0, length + r]
p3 = [0 + r, length]
- edges.append(Part.Edge(Part.Arc(FreeCAD.Base.Vector(p1[0], p1[1], 0), FreeCAD.Base.Vector(p2[0], p2[1], 0), FreeCAD.Base.Vector(p3[0], p3[1], 0))))
- #wir.append(Part.Arc(FreeCAD.Base.Vector(p1[0], p1[1], 0), FreeCAD.Base.Vector(p2[0], p2[1], 0), FreeCAD.Base.Vector(p3[0], p3[1], 0)))
+ edges.append(
+ Part.Edge(
+ Part.Arc(
+ FreeCAD.Base.Vector(p1[0], p1[1], 0),
+ FreeCAD.Base.Vector(p2[0], p2[1], 0),
+ FreeCAD.Base.Vector(p3[0], p3[1], 0),
+ ),
+ ),
+ )
+ # wir.append(Part.Arc(FreeCAD.Base.Vector(p1[0], p1[1], 0), FreeCAD.Base.Vector(p2[0], p2[1], 0), FreeCAD.Base.Vector(p3[0], p3[1], 0)))
sortedEdges = Part.__sortEdges__(edges)
-
- #mainObj = Part.Shape(wir)
+
+ # mainObj = Part.Shape(wir)
##mainObj = wir.toShape()
## sayw(wir)
- #mainObj = Part.Wire(mainObj.Edges)
+ # mainObj = Part.Wire(mainObj.Edges)
##mainObj = Part.Face(mainObj)
- #mainObj=makeFace(Part.Wire(mainObj))
+ # mainObj=makeFace(Part.Wire(mainObj))
##mainObj = Part.Wire(wir)
##mainObj = Part.Face(mainObj)
wire = Part.Wire(sortedEdges)
mainObj = Part.Face(wire)
- #Part.show(mainObj)
-
- pos_1 = FreeCAD.Base.Vector(x1, y1, z_silk_offset) #z offset Front Silk 0.1
+ # Part.show(mainObj)
+
+ pos_1 = FreeCAD.Base.Vector(x1, y1, z_silk_offset) # z offset Front Silk 0.1
center = FreeCAD.Base.Vector(0, 0, 0)
rot = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), iang)
mainObj.Placement = FreeCAD.Base.Placement(pos_1, rot, center)
- #Part.show(mainObj)
- #stop
-
+ # Part.show(mainObj)
+ # stop
+
return mainObj
+
+
###
def addPadLong2(x, y, dx, dy, perc, typ, z_off, type=None, ratio=None):
- #pad center x,y pad dimension dx,dy, type, z offset
- #if ratio is not None:
+ # pad center x,y pad dimension dx,dy, type, z offset
+ # if ratio is not None:
# sayw(type);sayerr(ratio)
- dx=dx/2.
- dy=dy/2.
- curve = 90.
+ dx = dx / 2.0
+ dy = dy / 2.0
+ curve = 90.0
if typ == 0: # %
- if perc > 100.:
- perc == 100.
- if dx > dy:
- e = dy * perc / 100.
- else:
- e = dx * perc / 100.
+ if perc > 100.0:
+ perc == 100.0
+ e = dy * perc / 100.0 if dx > dy else dx * perc / 100.0
else: # mm
e = perc
if ratio is not None:
- #rratio=r1/min(sx,sy)
- e = float(ratio) * 2.0 * min(dx,dy)
- #sayerr(e)
+ # rratio=r1/min(sx,sy)
+ e = float(ratio) * 2.0 * min(dx, dy)
+ # sayerr(e)
p1 = [x - dx + e, y - dy, z_off]
p2 = [x + dx - e, y - dy, z_off]
p3 = [x + dx, y - dy + e, z_off]
@@ -9592,47 +10387,70 @@ def addPadLong2(x, y, dx, dy, perc, typ, z_off, type=None, ratio=None):
p6 = [x - dx + e, y + dy, z_off]
p7 = [x - dx, y + dy - e, z_off]
p8 = [x - dx, y - dy + e, z_off]
- #
points = []
if p1 != p2:
points.append(PLine(FreeCAD.Base.Vector(p1[0], p1[1], z_off), FreeCAD.Base.Vector(p2[0], p2[1], z_off)))
if p2 != p3:
p9 = arcMidPoint(p2, p3, curve)
- points.append(Part.Arc(FreeCAD.Base.Vector(p2[0], p2[1], z_off), FreeCAD.Base.Vector(p9[0], p9[1], z_off), FreeCAD.Base.Vector(p3[0], p3[1], z_off)))
+ points.append(
+ Part.Arc(
+ FreeCAD.Base.Vector(p2[0], p2[1], z_off),
+ FreeCAD.Base.Vector(p9[0], p9[1], z_off),
+ FreeCAD.Base.Vector(p3[0], p3[1], z_off),
+ ),
+ )
if p3 != p4:
points.append(PLine(FreeCAD.Base.Vector(p3[0], p3[1], z_off), FreeCAD.Base.Vector(p4[0], p4[1], z_off)))
if p4 != p5:
p10 = arcMidPoint(p4, p5, curve)
- points.append(Part.Arc(FreeCAD.Base.Vector(p4[0], p4[1], z_off), FreeCAD.Base.Vector(p10[0], p10[1], z_off), FreeCAD.Base.Vector(p5[0], p5[1], z_off)))
+ points.append(
+ Part.Arc(
+ FreeCAD.Base.Vector(p4[0], p4[1], z_off),
+ FreeCAD.Base.Vector(p10[0], p10[1], z_off),
+ FreeCAD.Base.Vector(p5[0], p5[1], z_off),
+ ),
+ )
if p5 != p6:
points.append(PLine(FreeCAD.Base.Vector(p5[0], p5[1], z_off), FreeCAD.Base.Vector(p6[0], p6[1], z_off)))
if p6 != p7:
p11 = arcMidPoint(p6, p7, curve)
- points.append(Part.Arc(FreeCAD.Base.Vector(p6[0], p6[1], z_off), FreeCAD.Base.Vector(p11[0], p11[1], z_off), FreeCAD.Base.Vector(p7[0], p7[1], z_off)))
+ points.append(
+ Part.Arc(
+ FreeCAD.Base.Vector(p6[0], p6[1], z_off),
+ FreeCAD.Base.Vector(p11[0], p11[1], z_off),
+ FreeCAD.Base.Vector(p7[0], p7[1], z_off),
+ ),
+ )
if p7 != p8:
points.append(PLine(FreeCAD.Base.Vector(p7[0], p7[1], z_off), FreeCAD.Base.Vector(p8[0], p8[1], z_off)))
if p8 != p1:
p12 = arcMidPoint(p8, p1, curve)
- points.append(Part.Arc(FreeCAD.Base.Vector(p8[0], p8[1], z_off), FreeCAD.Base.Vector(p12[0], p12[1], z_off), FreeCAD.Base.Vector(p1[0], p1[1], z_off)))
-
- if dx==dy and type != "rect" and type != "roundrect": # "circle"
- r=dx
- obj=[Part.Circle(FreeCAD.Vector(x, y, z_off), FreeCAD.Vector(0, 0, 1), r).toShape()]
- obj=Part.Wire(obj) #maui evaluate FC0.17
- #obj=Draft.makeWire(obj,closed=True,face=False,support=None) # create the wire
- #Part.show(obj)
- #stop
+ points.append(
+ Part.Arc(
+ FreeCAD.Base.Vector(p8[0], p8[1], z_off),
+ FreeCAD.Base.Vector(p12[0], p12[1], z_off),
+ FreeCAD.Base.Vector(p1[0], p1[1], z_off),
+ ),
+ )
+
+ if dx == dy and type not in {"rect", "roundrect"}: # "circle"
+ r = dx
+ obj = [Part.Circle(FreeCAD.Vector(x, y, z_off), FreeCAD.Vector(0, 0, 1), r).toShape()]
+ obj = Part.Wire(obj) # maui evaluate FC0.17
+ # obj=Draft.makeWire(obj,closed=True,face=False,support=None) # create the wire
+ # Part.show(obj)
+ # stop
else:
# obj = Part.Shape(points) #maui evaluate FC0.17
# #obj=[points.toShape()]
# obj = Part.Wire(obj.Edges) #maui evaluate FC0.17
- objs=[] # asm3 Links compatible way
+ objs = [] # asm3 Links compatible way
for e in points:
objs.append(e.toShape())
obj = Part.Wire(objs)
- #obj=Draft.makeWire(obj.Edges,closed=True,face=False,support=None) # create the wire
+ # obj=Draft.makeWire(obj.Edges,closed=True,face=False,support=None) # create the wire
- #if hole==0:
+ # if hole==0:
# obj = makeFace(obj)
###return makeFace(obj)
##list=[]
@@ -9641,19 +10459,17 @@ def addPadLong2(x, y, dx, dy, perc, typ, z_off, type=None, ratio=None):
##return obj1
return obj
+
###
def addPadLong(x, y, dx, dy, perc, typ, z_off):
- # center x,y dimension x,y, type, z offset
- dx=dx/2
- dy=dy/2
- curve = 90.
+ # center x,y dimension x,y, type, z offset
+ dx = dx / 2
+ dy = dy / 2
+ curve = 90.0
if typ == 0: # %
- if perc > 100.:
- perc == 100.
- if dx > dy:
- e = dy * perc / 100.
- else:
- e = dx * perc / 100.
+ if perc > 100.0:
+ perc == 100.0
+ e = dy * perc / 100.0 if dx > dy else dx * perc / 100.0
else: # mm
e = perc
p1 = [x - dx + e, y - dy, z_off]
@@ -9664,197 +10480,217 @@ def addPadLong(x, y, dx, dy, perc, typ, z_off):
p6 = [x - dx + e, y + dy, z_off]
p7 = [x - dx, y + dy - e, z_off]
p8 = [x - dx, y - dy + e, z_off]
- #
points = []
if p1 != p2:
points.append(PLine(FreeCAD.Base.Vector(p1[0], p1[1], z_off), FreeCAD.Base.Vector(p2[0], p2[1], z_off)))
if p2 != p3:
p9 = arcMidPoint(p2, p3, curve)
- points.append(Part.Arc(FreeCAD.Base.Vector(p2[0], p2[1], z_off), FreeCAD.Base.Vector(p9[0], p9[1], z_off), FreeCAD.Base.Vector(p3[0], p3[1], z_off)))
+ points.append(
+ Part.Arc(
+ FreeCAD.Base.Vector(p2[0], p2[1], z_off),
+ FreeCAD.Base.Vector(p9[0], p9[1], z_off),
+ FreeCAD.Base.Vector(p3[0], p3[1], z_off),
+ ),
+ )
if p3 != p4:
points.append(PLine(FreeCAD.Base.Vector(p3[0], p3[1], z_off), FreeCAD.Base.Vector(p4[0], p4[1], z_off)))
if p4 != p5:
p10 = arcMidPoint(p4, p5, curve)
- points.append(Part.Arc(FreeCAD.Base.Vector(p4[0], p4[1], z_off), FreeCAD.Base.Vector(p10[0], p10[1], z_off), FreeCAD.Base.Vector(p5[0], p5[1], z_off)))
+ points.append(
+ Part.Arc(
+ FreeCAD.Base.Vector(p4[0], p4[1], z_off),
+ FreeCAD.Base.Vector(p10[0], p10[1], z_off),
+ FreeCAD.Base.Vector(p5[0], p5[1], z_off),
+ ),
+ )
if p5 != p6:
points.append(PLine(FreeCAD.Base.Vector(p5[0], p5[1], z_off), FreeCAD.Base.Vector(p6[0], p6[1], z_off)))
if p6 != p7:
p11 = arcMidPoint(p6, p7, curve)
- points.append(Part.Arc(FreeCAD.Base.Vector(p6[0], p6[1], z_off), FreeCAD.Base.Vector(p11[0], p11[1], z_off), FreeCAD.Base.Vector(p7[0], p7[1], z_off)))
+ points.append(
+ Part.Arc(
+ FreeCAD.Base.Vector(p6[0], p6[1], z_off),
+ FreeCAD.Base.Vector(p11[0], p11[1], z_off),
+ FreeCAD.Base.Vector(p7[0], p7[1], z_off),
+ ),
+ )
if p7 != p8:
points.append(PLine(FreeCAD.Base.Vector(p7[0], p7[1], z_off), FreeCAD.Base.Vector(p8[0], p8[1], z_off)))
if p8 != p1:
p12 = arcMidPoint(p8, p1, curve)
- points.append(Part.Arc(FreeCAD.Base.Vector(p8[0], p8[1], z_off), FreeCAD.Base.Vector(p12[0], p12[1], z_off), FreeCAD.Base.Vector(p1[0], p1[1], z_off)))
+ points.append(
+ Part.Arc(
+ FreeCAD.Base.Vector(p8[0], p8[1], z_off),
+ FreeCAD.Base.Vector(p12[0], p12[1], z_off),
+ FreeCAD.Base.Vector(p1[0], p1[1], z_off),
+ ),
+ )
- if dx==dy: # "circle"
- r=dx
- obj=[Part.Circle(FreeCAD.Vector(x, y, z_off), FreeCAD.Vector(0, 0, 1), r).toShape()]
- obj=Part.Wire(obj)
+ if dx == dy: # "circle"
+ r = dx
+ obj = [Part.Circle(FreeCAD.Vector(x, y, z_off), FreeCAD.Vector(0, 0, 1), r).toShape()]
+ obj = Part.Wire(obj)
else:
# obj = Part.Shape(points)
# obj = Part.Wire(obj.Edges)
- objs=[] # asm3 Links compatible way
+ objs = [] # asm3 Links compatible way
for e in points:
objs.append(e.toShape())
obj = Part.Wire(objs)
obj = makeFace(obj)
- #return makeFace(obj)
- list=[]
+ # return makeFace(obj)
+ list = []
list.append(obj)
- obj1=Part.makeCompound(list)
- return obj1
+ return Part.makeCompound(list)
+
+
###
def cutHole2(mainObj, holep, holed):
if holed[1] > min_val:
- #hole = [Part.Circle(FreeCAD.Vector(hole[0], hole[1]), FreeCAD.Vector(0, 0, 1), hole[2]).toShape()]
- z_off=0
+ # hole = [Part.Circle(FreeCAD.Vector(hole[0], hole[1]), FreeCAD.Vector(0, 0, 1), hole[2]).toShape()]
+ z_off = 0
hole = addPadLong(holep[0], holep[1], holed[0], holed[1], 100, 0, z_off)
mainObj = mainObj.cut(hole)
Part.show(mainObj)
return mainObj
+
+
###
###
-def createPad2(x,y,sx,sy,dcx,dcy,dx,dy,type,layer):
+def createPad2(x, y, sx, sy, dcx, dcy, dx, dy, type, layer):
##pad pos x,y; pad size x,y; drillcenter x,y; drill size x,y, layer
- z_offset=0
- remove=1
- if type=="oval":
- perc=100
- tp=0
- else:
- perc=0
- tp=0
- if layer=="top":
- thick=-0.01
- z_offset=0
+ z_offset = 0
+ if type == "oval":
+ perc = 100
+ tp = 0
else:
- thick=0.01
- z_offset=-1.6
- #say(str(x)+"x "+str(y)+"y "+str(sx)+"sx "+str(sy)+"sy ")
- #say(str(dcx)+"dcx "+str(dcy)+"dcy "+str(dx)+"dx "+str(dy)+"dy ")
- mypad=addPadLong2(x, y, sx, sy, perc, tp, z_offset)
+ perc = 0
+ tp = 0
+ z_offset = 0 if layer == "top" else -1.6
+ # say(str(x)+"x "+str(y)+"y "+str(sx)+"sx "+str(sy)+"sy ")
+ # say(str(dcx)+"dcx "+str(dcy)+"dcy "+str(dx)+"dx "+str(dy)+"dy ")
+ mypad = addPadLong2(x, y, sx, sy, perc, tp, z_offset)
Part.show(mypad)
- FreeCAD.ActiveDocument.ActiveObject.Label="mypad"
- pad_name=FreeCAD.ActiveDocument.ActiveObject.Name
- if dx!=0:
- perc=100 #drill always oval
- tp=0
- mydrill=addPadLong2(dcx, dcy, dx, dy, perc, tp, 0)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "mypad"
+ pad_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ if dx != 0:
+ perc = 100 # drill always oval
+ tp = 0
+ mydrill = addPadLong2(dcx, dcy, dx, dy, perc, tp, 0)
Part.show(mydrill)
- FreeCAD.ActiveDocument.ActiveObject.Label="mydrill"
- drill_name=FreeCAD.ActiveDocument.ActiveObject.Name
- myannular=addPadLong2(dcx, dcy, dx+0.01, dy+0.01, perc, tp, 0)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "mydrill"
+ drill_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ myannular = addPadLong2(dcx, dcy, dx + 0.01, dy + 0.01, perc, tp, 0)
Part.show(myannular)
- FreeCAD.ActiveDocument.ActiveObject.Label="myannular"
- ann_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #myhole=addPadLong2(dcx, dcy, dx, dy, perc, tp, z_offset)
- #Part.show(myhole)
- #FreeCAD.ActiveDocument.ActiveObject.Label="myhole"
+ FreeCAD.ActiveDocument.ActiveObject.Label = "myannular"
+ ann_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ # myhole=addPadLong2(dcx, dcy, dx, dy, perc, tp, z_offset)
+ # Part.show(myhole)
+ # FreeCAD.ActiveDocument.ActiveObject.Label="myhole"
# workaround FC 0.17 OCC 7
try:
- if float(Part.OCC_VERSION.split('.')[0]) >= 7:
+ if float(Part.OCC_VERSION.split(".")[0]) >= 7:
mydrill.reverse()
except:
pass
- wire = [mypad,mydrill]
- wire2 = [myannular,mydrill]
+ wire = [mypad, mydrill]
+ wire2 = [myannular, mydrill]
face = Part.Face(wire)
face2 = Part.Face(mydrill)
face3 = Part.Face(wire2)
- extr = face.extrude(FreeCAD.Vector(0,0,-.01))
+ extr = face.extrude(FreeCAD.Vector(0, 0, -0.01))
Part.show(extr)
- FreeCAD.ActiveDocument.ActiveObject.Label="drilled_pad"
- extr2 = face2.extrude(FreeCAD.Vector(0,0,-1.58))
+ FreeCAD.ActiveDocument.ActiveObject.Label = "drilled_pad"
+ extr2 = face2.extrude(FreeCAD.Vector(0, 0, -1.58))
Part.show(extr2)
- FreeCAD.ActiveDocument.ActiveObject.Label="hole"
- extr3 = face3.extrude(FreeCAD.Vector(0,0,-1.58))
+ FreeCAD.ActiveDocument.ActiveObject.Label = "hole"
+ extr3 = face3.extrude(FreeCAD.Vector(0, 0, -1.58))
Part.show(extr3)
- FreeCAD.ActiveDocument.ActiveObject.Label="annular"
+ FreeCAD.ActiveDocument.ActiveObject.Label = "annular"
FreeCAD.ActiveDocument.removeObject(pad_name)
FreeCAD.ActiveDocument.removeObject(drill_name)
FreeCAD.ActiveDocument.removeObject(ann_name)
FreeCAD.ActiveDocument.recompute()
else:
face = Part.Face(mypad)
- extr = face.extrude(FreeCAD.Vector(0,0,-.01))
+ extr = face.extrude(FreeCAD.Vector(0, 0, -0.01))
Part.show(extr)
- FreeCAD.ActiveDocument.ActiveObject.Label="smd_pad"
+ FreeCAD.ActiveDocument.ActiveObject.Label = "smd_pad"
FreeCAD.ActiveDocument.removeObject(pad_name)
FreeCAD.ActiveDocument.recompute()
return extr
+
+
###
-def createPad(x,y,sx,sy,dcx,dcy,dx,dy,type,layer):
+def createPad(x, y, sx, sy, dcx, dcy, dx, dy, type, layer):
##pad pos x,y; pad size x,y; drillcenter x,y; drill size x,y
- z_offset=0
- remove=1
- if type=="oval":
- perc=100
- tp=0
+ z_offset = 0
+ remove = 1
+ if type == "oval":
+ perc = 100
+ tp = 0
else:
- perc=0
- tp=0
- if layer=="top":
- thick=-0.01
- z_offset=0
+ perc = 0
+ tp = 0
+ if layer == "top":
+ thick = -0.01
+ z_offset = 0
else:
- thick=0.01
- z_offset=-1.6
- #say(str(x)+"x "+str(y)+"y "+str(sx)+"sx "+str(sy)+"sy ")
- #say(str(dcx)+"dcx "+str(dcy)+"dcy "+str(dx)+"dx "+str(dy)+"dy ")
- mypad=addPadLong(x, y, sx, sy, perc, tp, z_offset)
+ thick = 0.01
+ z_offset = -1.6
+ # say(str(x)+"x "+str(y)+"y "+str(sx)+"sx "+str(sy)+"sy ")
+ # say(str(dcx)+"dcx "+str(dcy)+"dcy "+str(dx)+"dx "+str(dy)+"dy ")
+ mypad = addPadLong(x, y, sx, sy, perc, tp, z_offset)
Part.show(mypad)
- FreeCAD.ActiveDocument.ActiveObject.Label="mypad"
- pad_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.addObject("Part::Extrusion","Extrude_pad")
- extrude_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.ActiveObject.Label = "mypad"
+ pad_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.addObject("Part::Extrusion", "Extrude_pad")
FreeCAD.ActiveDocument.Extrude_pad.Base = FreeCAD.ActiveDocument.getObject(pad_name)
- FreeCAD.ActiveDocument.Extrude_pad.Dir = (0,0,thick)
- FreeCAD.ActiveDocument.Extrude_pad.Solid = (True)
- FreeCAD.ActiveDocument.Extrude_pad.TaperAngle = (0)
+ FreeCAD.ActiveDocument.Extrude_pad.Dir = (0, 0, thick)
+ FreeCAD.ActiveDocument.Extrude_pad.Solid = True
+ FreeCAD.ActiveDocument.Extrude_pad.TaperAngle = 0
FreeCADGui.ActiveDocument.getObject(pad_name).Visibility = False
- FreeCAD.ActiveDocument.Extrude_pad.Label = 'mypad_solid'
- extrude_pad_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #FreeCAD.ActiveDocument.recompute()
- if dx!=0:
- perc=100 #drill always oval
- mydrill=addPadLong(dcx, dcy, dx, dy, perc, tp, z_offset)
+ FreeCAD.ActiveDocument.Extrude_pad.Label = "mypad_solid"
+ extrude_pad_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ # FreeCAD.ActiveDocument.recompute()
+ if dx != 0:
+ perc = 100 # drill always oval
+ mydrill = addPadLong(dcx, dcy, dx, dy, perc, tp, z_offset)
# workaround FC 0.17 OCC 7
try:
- if float(Part.OCC_VERSION.split('.')[0]) >= 7:
+ if float(Part.OCC_VERSION.split(".")[0]) >= 7:
mydrill.reverse()
except:
pass
Part.show(mydrill)
- FreeCAD.ActiveDocument.ActiveObject.Label="mydrill"
- drill_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.addObject("Part::Extrusion","Extrude_d")
- extrude_d_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.ActiveObject.Label = "mydrill"
+ drill_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.addObject("Part::Extrusion", "Extrude_d")
FreeCAD.ActiveDocument.Extrude_d.Base = FreeCAD.ActiveDocument.getObject(drill_name)
- FreeCAD.ActiveDocument.Extrude_d.Dir = (0,0,thick)
- FreeCAD.ActiveDocument.Extrude_d.Solid = (True)
- FreeCAD.ActiveDocument.Extrude_d.TaperAngle = (0)
+ FreeCAD.ActiveDocument.Extrude_d.Dir = (0, 0, thick)
+ FreeCAD.ActiveDocument.Extrude_d.Solid = True
+ FreeCAD.ActiveDocument.Extrude_d.TaperAngle = 0
FreeCADGui.ActiveDocument.getObject(drill_name).Visibility = False
- FreeCAD.ActiveDocument.Extrude_d.Label = 'mydrill_solid'
- extrude_drill_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #FreeCAD.ActiveDocument.recompute()
+ FreeCAD.ActiveDocument.Extrude_d.Label = "mydrill_solid"
+ extrude_drill_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ # FreeCAD.ActiveDocument.recompute()
- FreeCAD.activeDocument().addObject("Part::Cut","myCut")
- cut_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.activeDocument().addObject("Part::Cut", "myCut")
+ cut_name = FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.activeDocument().getObject(cut_name).Base = FreeCAD.activeDocument().Extrude_pad
FreeCAD.activeDocument().getObject(cut_name).Tool = FreeCAD.activeDocument().Extrude_d
- FreeCADGui.activeDocument().Extrude_pad.Visibility=False
- FreeCADGui.activeDocument().Extrude_d.Visibility=False
- #FreeCADGui.ActiveDocument.getObject(cut_name).ShapeColor=FreeCADGui.ActiveDocument.Extrude.ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81,0.71,0.23) #(0.85,0.53,0.10)
- FreeCADGui.ActiveDocument.ActiveObject.DisplayMode=FreeCADGui.ActiveDocument.Extrude_pad.DisplayMode
+ FreeCADGui.activeDocument().Extrude_pad.Visibility = False
+ FreeCADGui.activeDocument().Extrude_d.Visibility = False
+ # FreeCADGui.ActiveDocument.getObject(cut_name).ShapeColor=FreeCADGui.ActiveDocument.Extrude.ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81, 0.71, 0.23) # (0.85,0.53,0.10)
+ FreeCADGui.ActiveDocument.ActiveObject.DisplayMode = FreeCADGui.ActiveDocument.Extrude_pad.DisplayMode
FreeCAD.ActiveDocument.recompute()
- pad_d_name="TH_Pad"
- FreeCAD.ActiveDocument.addObject('Part::Feature',pad_d_name).Shape=FreeCAD.ActiveDocument.ActiveObject.Shape
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81,0.71,0.23) #(0.85,0.53,0.10)
- myObj=FreeCAD.ActiveDocument.getObject(pad_d_name)
- if remove==1:
+ pad_d_name = "TH_Pad"
+ FreeCAD.ActiveDocument.addObject("Part::Feature", pad_d_name).Shape = FreeCAD.ActiveDocument.ActiveObject.Shape
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81, 0.71, 0.23) # (0.85,0.53,0.10)
+ myObj = FreeCAD.ActiveDocument.getObject(pad_d_name)
+ if remove == 1:
FreeCAD.ActiveDocument.removeObject(cut_name)
FreeCAD.ActiveDocument.removeObject(extrude_pad_name)
FreeCAD.ActiveDocument.removeObject(pad_name)
@@ -9863,148 +10699,147 @@ def createPad(x,y,sx,sy,dcx,dcy,dx,dy,type,layer):
FreeCAD.ActiveDocument.recompute()
else:
FreeCAD.ActiveDocument.recompute()
- pad_d_name="smdPad"
- FreeCAD.ActiveDocument.addObject('Part::Feature',pad_d_name).Shape=FreeCAD.ActiveDocument.ActiveObject.Shape
- myObj=FreeCAD.ActiveDocument.getObject(pad_d_name)
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81,0.71,0.23) #(0.85,0.53,0.10)
+ pad_d_name = "smdPad"
+ FreeCAD.ActiveDocument.addObject("Part::Feature", pad_d_name).Shape = FreeCAD.ActiveDocument.ActiveObject.Shape
+ myObj = FreeCAD.ActiveDocument.getObject(pad_d_name)
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81, 0.71, 0.23) # (0.85,0.53,0.10)
FreeCAD.ActiveDocument.removeObject(extrude_pad_name)
FreeCAD.ActiveDocument.removeObject(pad_name)
FreeCAD.ActiveDocument.recompute()
return myObj
+
+
###
-def createPad3(x,y,sx,sy,dcx,dcy,dx,dy,type,layer, ratio=None):
+def createPad3(x, y, sx, sy, dcx, dcy, dx, dy, type, layer, ratio=None):
##pad pos x,y; pad size x,y; drillcenter x,y; drill size x,y, type, layer, rratio
- z_offset=0
- remove=1
- if type=="oval" or type=="circle":
- perc=100
- tp=0
+ z_offset = 0
+ if type in {"oval", "circle"}:
+ perc = 100
+ tp = 0
else:
- perc=0
- tp=0
- if layer=="top":
- thick=-0.01
- z_offset=0
+ perc = 0
+ tp = 0
+ if layer == "top":
+ thick = -0.01
+ z_offset = 0
else:
- thick=0.01
- z_offset=-1.6
- #say(str(x)+"x "+str(y)+"y "+str(sx)+"sx "+str(sy)+"sy ")
- #say(str(dcx)+"dcx "+str(dcy)+"dcy "+str(dx)+"dx "+str(dy)+"dy ")
- mypad=addPadLong2(x, y, sx, sy, perc, tp, z_offset, type, ratio)
+ thick = 0.01
+ z_offset = -1.6
+ # say(str(x)+"x "+str(y)+"y "+str(sx)+"sx "+str(sy)+"sy ")
+ # say(str(dcx)+"dcx "+str(dcy)+"dcy "+str(dx)+"dx "+str(dy)+"dy ")
+ mypad = addPadLong2(x, y, sx, sy, perc, tp, z_offset, type, ratio)
Part.show(mypad)
- FreeCAD.ActiveDocument.ActiveObject.Label="mypad"
- pad_name=FreeCAD.ActiveDocument.ActiveObject.Name
- if dx!=0:
- perc=100 #drill always oval
- tp=0
- mydrill=addPadLong2(dcx, dcy, dx, dy, perc, tp, z_offset)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "mypad"
+ pad_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ if dx != 0:
+ perc = 100 # drill always oval
+ tp = 0
+ mydrill = addPadLong2(dcx, dcy, dx, dy, perc, tp, z_offset)
# workaround FC 0.17 OCC 7
try:
- if float(Part.OCC_VERSION.split('.')[0]) >= 7:
+ if float(Part.OCC_VERSION.split(".")[0]) >= 7:
mydrill.reverse()
except:
pass
- if test_flag_pads==True:
+ if test_flag_pads:
Part.show(mydrill)
- FreeCAD.ActiveDocument.ActiveObject.Label="mydrill"
- drill_name=FreeCAD.ActiveDocument.ActiveObject.Name
- myannular=addPadLong2(dcx, dcy, dx+0.01, dy+0.01, perc, tp, z_offset)
- if test_flag_pads==True:
+ FreeCAD.ActiveDocument.ActiveObject.Label = "mydrill"
+ myannular = addPadLong2(dcx, dcy, dx + 0.01, dy + 0.01, perc, tp, z_offset)
+ if test_flag_pads:
Part.show(myannular)
- FreeCAD.ActiveDocument.ActiveObject.Label="myannular"
- ann_name=FreeCAD.ActiveDocument.ActiveObject.Name
- myhole=addPadLong2(dcx, dcy, dx, dy, perc, tp, z_offset)
- if test_flag_pads==True:
+ FreeCAD.ActiveDocument.ActiveObject.Label = "myannular"
+ myhole = addPadLong2(dcx, dcy, dx, dy, perc, tp, z_offset)
+ if test_flag_pads:
Part.show(myhole)
- FreeCAD.ActiveDocument.ActiveObject.Label="myhole"
- wire = [mypad,mydrill]
- face = Part.Face(wire)
- extr = face.extrude(FreeCAD.Vector(0,0,thick))
- if test_flag_pads==True:
+ FreeCAD.ActiveDocument.ActiveObject.Label = "myhole"
+ wire = [mypad, mydrill]
+ face = Part.Face(wire)
+ extr = face.extrude(FreeCAD.Vector(0, 0, thick))
+ if test_flag_pads:
Part.show(extr)
- FreeCAD.ActiveDocument.ActiveObject.Label="drilled_pad"
- #Part.show(extr)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "drilled_pad"
+ # Part.show(extr)
FreeCAD.ActiveDocument.removeObject(pad_name)
FreeCAD.ActiveDocument.recompute()
else:
face = Part.Face(mypad)
- extr = face.extrude(FreeCAD.Vector(0,0,thick))
- #Part.show(extr)
- #FreeCAD.ActiveDocument.ActiveObject.Label="smd_pad"
+ extr = face.extrude(FreeCAD.Vector(0, 0, thick))
+ # Part.show(extr)
+ # FreeCAD.ActiveDocument.ActiveObject.Label="smd_pad"
FreeCAD.ActiveDocument.removeObject(pad_name)
FreeCAD.ActiveDocument.recompute()
return extr
+
+
###
-def createPad(x,y,sx,sy,dcx,dcy,dx,dy,type,layer):
+def createPad(x, y, sx, sy, dcx, dcy, dx, dy, type, layer): # noqa: F811
##pad pos x,y; pad size x,y; drillcenter x,y; drill size x,y
- z_offset=0
- remove=1
- if type=="oval":
- perc=100
- tp=0
+ z_offset = 0
+ remove = 1
+ if type == "oval":
+ perc = 100
+ tp = 0
else:
- perc=0
- tp=0
- if layer=="top":
- thick=-0.01
- z_offset=0
+ perc = 0
+ tp = 0
+ if layer == "top":
+ thick = -0.01
+ z_offset = 0
else:
- thick=0.01
- z_offset=-1.6
- #say(str(x)+"x "+str(y)+"y "+str(sx)+"sx "+str(sy)+"sy ")
- #say(str(dcx)+"dcx "+str(dcy)+"dcy "+str(dx)+"dx "+str(dy)+"dy ")
- mypad=addPadLong(x, y, sx, sy, perc, tp, z_offset)
+ thick = 0.01
+ z_offset = -1.6
+ # say(str(x)+"x "+str(y)+"y "+str(sx)+"sx "+str(sy)+"sy ")
+ # say(str(dcx)+"dcx "+str(dcy)+"dcy "+str(dx)+"dx "+str(dy)+"dy ")
+ mypad = addPadLong(x, y, sx, sy, perc, tp, z_offset)
Part.show(mypad)
- FreeCAD.ActiveDocument.ActiveObject.Label="mypad"
- pad_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.addObject("Part::Extrusion","Extrude_pad")
- extrude_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.ActiveObject.Label = "mypad"
+ pad_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.addObject("Part::Extrusion", "Extrude_pad")
FreeCAD.ActiveDocument.Extrude_pad.Base = FreeCAD.ActiveDocument.getObject(pad_name)
- FreeCAD.ActiveDocument.Extrude_pad.Dir = (0,0,thick)
- FreeCAD.ActiveDocument.Extrude_pad.Solid = (True)
- FreeCAD.ActiveDocument.Extrude_pad.TaperAngle = (0)
+ FreeCAD.ActiveDocument.Extrude_pad.Dir = (0, 0, thick)
+ FreeCAD.ActiveDocument.Extrude_pad.Solid = True
+ FreeCAD.ActiveDocument.Extrude_pad.TaperAngle = 0
FreeCADGui.ActiveDocument.getObject(pad_name).Visibility = False
- FreeCAD.ActiveDocument.Extrude_pad.Label = 'mypad_solid'
- extrude_pad_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #FreeCAD.ActiveDocument.recompute()
- if dx!=0:
- perc=100 #drill always oval
- mydrill=addPadLong(dcx, dcy, dx, dy, perc, tp, z_offset)
+ FreeCAD.ActiveDocument.Extrude_pad.Label = "mypad_solid"
+ extrude_pad_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ # FreeCAD.ActiveDocument.recompute()
+ if dx != 0:
+ perc = 100 # drill always oval
+ mydrill = addPadLong(dcx, dcy, dx, dy, perc, tp, z_offset)
# workaround FC 0.17 OCC 7
try:
- if float(Part.OCC_VERSION.split('.')[0]) >= 7:
+ if float(Part.OCC_VERSION.split(".")[0]) >= 7:
mydrill.reverse()
except:
pass
Part.show(mydrill)
- FreeCAD.ActiveDocument.ActiveObject.Label="mydrill"
- drill_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.addObject("Part::Extrusion","Extrude_d")
- extrude_d_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.ActiveObject.Label = "mydrill"
+ drill_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.addObject("Part::Extrusion", "Extrude_d")
FreeCAD.ActiveDocument.Extrude_d.Base = FreeCAD.ActiveDocument.getObject(drill_name)
- FreeCAD.ActiveDocument.Extrude_d.Dir = (0,0,thick)
- FreeCAD.ActiveDocument.Extrude_d.Solid = (True)
- FreeCAD.ActiveDocument.Extrude_d.TaperAngle = (0)
+ FreeCAD.ActiveDocument.Extrude_d.Dir = (0, 0, thick)
+ FreeCAD.ActiveDocument.Extrude_d.Solid = True
+ FreeCAD.ActiveDocument.Extrude_d.TaperAngle = 0
FreeCADGui.ActiveDocument.getObject(drill_name).Visibility = False
- FreeCAD.ActiveDocument.Extrude_d.Label = 'mydrill_solid'
- extrude_drill_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #FreeCAD.ActiveDocument.recompute()
+ FreeCAD.ActiveDocument.Extrude_d.Label = "mydrill_solid"
+ extrude_drill_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ # FreeCAD.ActiveDocument.recompute()
- FreeCAD.activeDocument().addObject("Part::Cut","myCut")
- cut_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.activeDocument().addObject("Part::Cut", "myCut")
+ cut_name = FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.activeDocument().getObject(cut_name).Base = FreeCAD.activeDocument().Extrude_pad
FreeCAD.activeDocument().getObject(cut_name).Tool = FreeCAD.activeDocument().Extrude_d
- FreeCADGui.activeDocument().Extrude_pad.Visibility=False
- FreeCADGui.activeDocument().Extrude_d.Visibility=False
- #FreeCADGui.ActiveDocument.getObject(cut_name).ShapeColor=FreeCADGui.ActiveDocument.Extrude.ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81,0.71,0.23) #(0.85,0.53,0.10)
- FreeCADGui.ActiveDocument.ActiveObject.DisplayMode=FreeCADGui.ActiveDocument.Extrude_pad.DisplayMode
+ FreeCADGui.activeDocument().Extrude_pad.Visibility = False
+ FreeCADGui.activeDocument().Extrude_d.Visibility = False
+ # FreeCADGui.ActiveDocument.getObject(cut_name).ShapeColor=FreeCADGui.ActiveDocument.Extrude.ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81, 0.71, 0.23) # (0.85,0.53,0.10)
+ FreeCADGui.ActiveDocument.ActiveObject.DisplayMode = FreeCADGui.ActiveDocument.Extrude_pad.DisplayMode
FreeCAD.ActiveDocument.recompute()
- pad_d_name="TH_Pad"
- FreeCAD.ActiveDocument.addObject('Part::Feature',pad_d_name).Shape=FreeCAD.ActiveDocument.ActiveObject.Shape
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81,0.71,0.23) #(0.85,0.53,0.10)
- myObj=FreeCAD.ActiveDocument.getObject(pad_d_name)
- if remove==1:
+ pad_d_name = "TH_Pad"
+ FreeCAD.ActiveDocument.addObject("Part::Feature", pad_d_name).Shape = FreeCAD.ActiveDocument.ActiveObject.Shape
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81, 0.71, 0.23) # (0.85,0.53,0.10)
+ myObj = FreeCAD.ActiveDocument.getObject(pad_d_name)
+ if remove == 1:
FreeCAD.ActiveDocument.removeObject(cut_name)
FreeCAD.ActiveDocument.removeObject(extrude_pad_name)
FreeCAD.ActiveDocument.removeObject(pad_name)
@@ -10013,494 +10848,501 @@ def createPad(x,y,sx,sy,dcx,dcy,dx,dy,type,layer):
FreeCAD.ActiveDocument.recompute()
else:
FreeCAD.ActiveDocument.recompute()
- pad_d_name="smdPad"
- FreeCAD.ActiveDocument.addObject('Part::Feature',pad_d_name).Shape=FreeCAD.ActiveDocument.ActiveObject.Shape
- myObj=FreeCAD.ActiveDocument.getObject(pad_d_name)
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81,0.71,0.23) #(0.85,0.53,0.10)
+ pad_d_name = "smdPad"
+ FreeCAD.ActiveDocument.addObject("Part::Feature", pad_d_name).Shape = FreeCAD.ActiveDocument.ActiveObject.Shape
+ myObj = FreeCAD.ActiveDocument.getObject(pad_d_name)
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81, 0.71, 0.23) # (0.85,0.53,0.10)
FreeCAD.ActiveDocument.removeObject(extrude_pad_name)
FreeCAD.ActiveDocument.removeObject(pad_name)
FreeCAD.ActiveDocument.recompute()
return myObj
+
+
###
-def createHole(x,y,dx,dy,type):
- if type=="oval":
- perc=100
- tp=0
+
+def createHole(x, y, dx, dy, type):
+ if type == "oval":
+ perc = 100
+ tp = 0
else:
- perc=0
- tp=0
- mydrill=addPadLong(x, y, dx, dy, perc, tp, 0)
+ perc = 0
+ tp = 0
+ mydrill = addPadLong(x, y, dx, dy, perc, tp, 0)
Part.show(mydrill)
- FreeCAD.ActiveDocument.ActiveObject.Label="mydrill"
- drill_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.addObject("Part::Extrusion","Extrude_d")
+ FreeCAD.ActiveDocument.ActiveObject.Label = "mydrill"
+ drill_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.addObject("Part::Extrusion", "Extrude_d")
FreeCAD.ActiveDocument.Extrude_d.Base = FreeCAD.ActiveDocument.getObject(drill_name)
- FreeCAD.ActiveDocument.Extrude_d.Dir = (0,0,-1.6)
- FreeCAD.ActiveDocument.Extrude_d.Solid = (True)
- FreeCAD.ActiveDocument.Extrude_d.TaperAngle = (0)
+ FreeCAD.ActiveDocument.Extrude_d.Dir = (0, 0, -1.6)
+ FreeCAD.ActiveDocument.Extrude_d.Solid = True
+ FreeCAD.ActiveDocument.Extrude_d.TaperAngle = 0
FreeCADGui.ActiveDocument.getObject(drill_name).Visibility = False
- FreeCAD.ActiveDocument.Extrude_d.Label = 'mydrill_hole'
- extrude_hole_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.Extrude_d.Label = "mydrill_hole"
+ extrude_hole_name = FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.recompute()
- hole_name="hole"
- FreeCAD.ActiveDocument.addObject('Part::Feature',hole_name).Shape=FreeCAD.ActiveDocument.getObject(extrude_hole_name).Shape
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.67,1.00,0.50)
+ hole_name = "hole"
+ FreeCAD.ActiveDocument.addObject("Part::Feature", hole_name).Shape = FreeCAD.ActiveDocument.getObject(
+ extrude_hole_name,
+ ).Shape
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.67, 1.00, 0.50)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 70
- myObj=FreeCADGui.ActiveDocument.ActiveObject
+ myObj = FreeCADGui.ActiveDocument.ActiveObject
FreeCAD.ActiveDocument.removeObject(drill_name)
FreeCAD.ActiveDocument.removeObject(extrude_hole_name)
FreeCAD.ActiveDocument.recompute()
return myObj
+
###
-def createHole2(x,y,dx,dy,type):
- if type=="oval" or type=="circle":
- perc=100
- tp=0
+def createHole2(x, y, dx, dy, type):
+ if type in {"oval", "circle"}:
+ perc = 100
+ tp = 0
else:
- perc=0
- tp=0
- #mydrill=addPadLong(x, y, dx, dy, perc, tp, -0.01)
- mydrill=addPadLong(x, y, dx, dy, perc, tp, .01)
+ perc = 0
+ tp = 0
+ # mydrill=addPadLong(x, y, dx, dy, perc, tp, -0.01)
+ mydrill = addPadLong(x, y, dx, dy, perc, tp, 0.01)
# workaround FC 0.17 OCC 7
try:
- if float(Part.OCC_VERSION.split('.')[0]) >= 7:
+ if float(Part.OCC_VERSION.split(".")[0]) >= 7:
mydrill.reverse()
except:
pass
- #Part.show(mydrill)
- #hole = mydrill.extrude(FreeCAD.Base.Vector(0, 0, -1.58))
+ # Part.show(mydrill)
+ # hole = mydrill.extrude(FreeCAD.Base.Vector(0, 0, -1.58))
hole = mydrill.extrude(FreeCAD.Base.Vector(0, 0, -1.61))
- holeModel=[]
+ holeModel = []
holeModel.append(hole)
- holeModel = Part.makeCompound(holeModel)
- #say("hereHole")
- #FreeCAD.ActiveDocument.recompute()
- return holeModel
+ return Part.makeCompound(holeModel)
+ # say("hereHole")
+ # FreeCAD.ActiveDocument.recompute()
+
###
-def createHole3(x,y,dx,dy,type,height):
- if type=="oval":
- perc=100
- tp=0
+def createHole3(x, y, dx, dy, type, height):
+ if type == "oval":
+ perc = 100
+ tp = 0
else:
- perc=0
- tp=0
- #mydrill=addPadLong(x, y, dx, dy, perc, tp, -0.01)
- mydrill=addPadLong(x, y, dx, dy, perc, tp, 0.1)
- #Part.show(mydrill)
- #hole = mydrill.extrude(FreeCAD.Base.Vector(0, 0, -1.58))
- hole = mydrill.extrude(FreeCAD.Base.Vector(0, 0, -(height+0.2)))
- holeModel=[]
+ perc = 0
+ tp = 0
+ # mydrill=addPadLong(x, y, dx, dy, perc, tp, -0.01)
+ mydrill = addPadLong(x, y, dx, dy, perc, tp, 0.1)
+ # Part.show(mydrill)
+ # hole = mydrill.extrude(FreeCAD.Base.Vector(0, 0, -1.58))
+ hole = mydrill.extrude(FreeCAD.Base.Vector(0, 0, -(height + 0.2)))
+ holeModel = []
holeModel.append(hole)
- holeModel = Part.makeCompound(holeModel)
- #say("hereHole")
- #FreeCAD.ActiveDocument.recompute()
+ return Part.makeCompound(holeModel)
+ # say("hereHole")
+ # FreeCAD.ActiveDocument.recompute()
- return holeModel
###
###
-def createHole4(x,y,dx,dy,type):
+def createHole4(x, y, dx, dy, type):
global show_shapes
- if type=="oval":
- perc=100
- tp=0
+ if type == "oval":
+ perc = 100
+ tp = 0
else:
- perc=0
- tp=0
- #mydrill=addPadLong(x, y, dx, dy, perc, tp, -0.01)
- #mydrill=addPadLong(x, y, dx, dy, perc, tp, .01)
- mydrill=addPadLong2(x, y, dx, dy, perc, tp, 0)
- holeModel=[]
- #holeModel.append(hole)
- #holeModel.append(mydrill)
+ perc = 0
+ tp = 0
+ # mydrill=addPadLong(x, y, dx, dy, perc, tp, -0.01)
+ # mydrill=addPadLong(x, y, dx, dy, perc, tp, .01)
+ mydrill = addPadLong2(x, y, dx, dy, perc, tp, 0)
+ holeModel = []
+ # holeModel.append(hole)
+ # holeModel.append(mydrill)
##holeModel = Part.makeCompound(holeModel)
- #holeModel = Part.Face(holeModel)
- face = OSCD2Dg_edgestofaces(mydrill.Edges,3 , edge_tolerance) #algo 0
- #face = OSCD2Dg_edgestofaces(mydrill.Edges,3 , edge_tolerance)
- face.fix(0,0,0)
+ # holeModel = Part.Face(holeModel)
+ face = OSCD2Dg_edgestofaces(mydrill.Edges, 3, edge_tolerance) # algo 0
+ # face = OSCD2Dg_edgestofaces(mydrill.Edges,3 , edge_tolerance)
+ face.fix(0, 0, 0)
if show_shapes:
Part.show(face)
holeModel = face
- #sayerr('x'+str(x)+' y'+str(y)+' dx'+str(dx)+' dy'+str(dy)+' perc'+str(perc)+' tp'+str(tp)+'0')
- #stop
- #say("hereHole")
- #FreeCAD.ActiveDocument.recompute()
- #return holeModel
+ # sayerr('x'+str(x)+' y'+str(y)+' dx'+str(dx)+' dy'+str(dy)+' perc'+str(perc)+' tp'+str(tp)+'0')
+ # stop
+ # say("hereHole")
+ # FreeCAD.ActiveDocument.recompute()
+ # return holeModel
return Part.makeCompound(holeModel)
+
###
-def createTHPlate(x,y,dx,dy,type):
- if type=="oval" or type=="circle":
- perc=100
- tp=0
+def createTHPlate(x, y, dx, dy, type):
+ if type in {"oval", "circle"}:
+ perc = 100
+ tp = 0
else:
- perc=0
- tp=0
- #mydrill=addPadLong(x, y, dx, dy, perc, tp, -0.01)
- mydrill=addPadLong2(x, y, dx, dy, perc, tp, -0.01)
+ perc = 0
+ tp = 0
+ # mydrill=addPadLong(x, y, dx, dy, perc, tp, -0.01)
+ mydrill = addPadLong2(x, y, dx, dy, perc, tp, -0.01)
# workaround FC 0.17 OCC 7
try:
- if float(Part.OCC_VERSION.split('.')[0]) >= 7:
+ if float(Part.OCC_VERSION.split(".")[0]) >= 7:
mydrill.reverse()
except:
pass
- myannular=addPadLong2(x, y, dx+0.01, dy+0.01, perc, tp, -0.01)
- wire2 = [myannular,mydrill]
+ myannular = addPadLong2(x, y, dx + 0.01, dy + 0.01, perc, tp, -0.01)
+ wire2 = [myannular, mydrill]
face3 = Part.Face(wire2)
- THP = face3.extrude(FreeCAD.Vector(0,0,-1.58))
- #Part.show(extr3)
- #FreeCAD.ActiveDocument.ActiveObject.Label="annular"
+ THP = face3.extrude(FreeCAD.Vector(0, 0, -1.58))
+ # Part.show(extr3)
+ # FreeCAD.ActiveDocument.ActiveObject.Label="annular"
##hole = mydrill.extrude(FreeCAD.Base.Vector(0, 0, -1.58))
- #THP = myannular.extrude(FreeCAD.Base.Vector(0, 0, -1.58))
- THPModel=[]
+ # THP = myannular.extrude(FreeCAD.Base.Vector(0, 0, -1.58))
+ THPModel = []
THPModel.append(THP)
- THPModel = Part.makeCompound(THPModel)
- #say("hereHole")
- #FreeCAD.ActiveDocument.recompute()
+ return Part.makeCompound(THPModel)
+ # say("hereHole")
+ # FreeCAD.ActiveDocument.recompute()
- return THPModel
###
def createGeomC(cx, cy, radius, layer, width):
- #createGeomC(Gcx, Gcy, GRad,'top', Gw)
- if layer == 'top':
- #if top==True:
- thick=-0.01
- z_offset=0
+ # createGeomC(Gcx, Gcy, GRad,'top', Gw)
+ if layer == "top":
+ # if top==True:
+ thick = -0.01
+ z_offset = 0
else:
- thick=0.01
- z_offset=-1.6
+ thick = 0.01
+ z_offset = -1.6
bv = Base.Vector
- circ = Part.makeCircle(radius+width/2, bv(cx,cy,z_offset))
+ circ = Part.makeCircle(radius + width / 2, bv(cx, cy, z_offset))
mw = Part.Wire(circ.Edges)
- myp= Part.Face(mw)
- #Part.show(mypad)
- circ = Part.makeCircle(radius-width/2, bv(cx,cy,z_offset))
+ myp = Part.Face(mw)
+ # Part.show(mypad)
+ circ = Part.makeCircle(radius - width / 2, bv(cx, cy, z_offset))
mw2 = Part.Wire(circ.Edges)
myp2 = Part.Face(mw2)
- mypad=myp.cut(myp2)
+ mypad = myp.cut(myp2)
Part.show(mypad)
- FreeCAD.ActiveDocument.ActiveObject.Label="mypad"
- pad_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.ActiveObject.Label = "mypad"
+ pad_name = FreeCAD.ActiveDocument.ActiveObject.Name
# face = Part.Face(mypad)
# Part.show(face)
- extr = mypad.extrude(FreeCAD.Vector(0,0,thick))
- #Part.show(extr)
- #FreeCAD.ActiveDocument.ActiveObject.Label="smd_pad"
+ extr = mypad.extrude(FreeCAD.Vector(0, 0, thick))
+ # Part.show(extr)
+ # FreeCAD.ActiveDocument.ActiveObject.Label="smd_pad"
FreeCAD.ActiveDocument.removeObject(pad_name)
FreeCAD.ActiveDocument.recompute()
- #extr = sface.extrude(FreeCAD.Vector(0,0,-.01))
- #Part.show(extr)
- #stop
-
+ # extr = sface.extrude(FreeCAD.Vector(0,0,-.01))
+ # Part.show(extr)
+ # stop
+
return extr
-
-def createPoly(x, y, sx, sy, dcx,dcy,dx,dy,pShape, layer, poly_points):
- #createPad3(x1, y1, dx, dy, xs, ys,rx,ry,pShape,'top')
- #createPad3(x, y, sx,sy, dcx,dcy,dx,dy,type,layer):
- pts=[]
+
+def createPoly(x, y, sx, sy, dcx, dcy, dx, dy, pShape, layer, poly_points):
+ # createPad3(x1, y1, dx, dy, xs, ys,rx,ry,pShape,'top')
+ # createPad3(x, y, sx,sy, dcx,dcy,dx,dy,type,layer):
+ pts = []
bv = Base.Vector
- p0 = poly_points[0].split(' ')
- if layer == 'top':
- #if top==True:
- thick=-0.01
- z_offset=0
+ p0 = poly_points[0].split(" ")
+ if layer == "top":
+ # if top==True:
+ thick = -0.01
+ z_offset = 0
else:
- thick=0.01
- z_offset=-1.6
+ thick = 0.01
+ z_offset = -1.6
for p in poly_points:
- pc = p.split(' ')
- pts.append(bv(float(pc[1])+x,-1*float(pc[2][0:pc[2].index(')')])+y,z_offset))
+ pc = p.split(" ")
+ pts.append(bv(float(pc[1]) + x, -1 * float(pc[2][0 : pc[2].index(")")]) + y, z_offset))
# print (float(pc[1])+x1,-1*float(pc[2][0:pc[2].index(')')])+y1,z_offset)
# closing poly
- pts.append(bv(float(p0[1])+x,-1*float(p0[2][0:p0[2].index(')')])+y,z_offset))
+ pts.append(bv(float(p0[1]) + x, -1 * float(p0[2][0 : p0[2].index(")")]) + y, z_offset))
# print (float(p0[1])+x1,-1*float(p0[2][0:p0[2].index(')')])+y1,z_offset)
# f = Draft.makeWire(pts,closed=True)
# obj=f.Shape.copy()
- lshape_wire = Part.makePolygon(pts)
+ lshape_wire = Part.makePolygon(pts)
mypad = Part.Face(lshape_wire)
Part.show(mypad)
- FreeCAD.ActiveDocument.ActiveObject.Label="mypad"
- pad_name=FreeCAD.ActiveDocument.ActiveObject.Name
- if dx!=0:
- perc=100 #drill always oval
- tp=0
- mydrill=addPadLong2(dcx, dcy, dx, dy, perc, tp, z_offset)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "mypad"
+ pad_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ if dx != 0:
+ perc = 100 # drill always oval
+ tp = 0
+ mydrill = addPadLong2(dcx, dcy, dx, dy, perc, tp, z_offset)
# workaround FC 0.17 OCC 7
try:
- if float(Part.OCC_VERSION.split('.')[0]) >= 7:
+ if float(Part.OCC_VERSION.split(".")[0]) >= 7:
mydrill.reverse()
except:
pass
- if test_flag_pads==True:
+ if test_flag_pads:
Part.show(mydrill)
- FreeCAD.ActiveDocument.ActiveObject.Label="mydrill"
- drill_name=FreeCAD.ActiveDocument.ActiveObject.Name
- myannular=addPadLong2(dcx, dcy, dx+0.01, dy+0.01, perc, tp, z_offset)
- if test_flag_pads==True:
+ FreeCAD.ActiveDocument.ActiveObject.Label = "mydrill"
+ myannular = addPadLong2(dcx, dcy, dx + 0.01, dy + 0.01, perc, tp, z_offset)
+ if test_flag_pads:
Part.show(myannular)
- FreeCAD.ActiveDocument.ActiveObject.Label="myannular"
- ann_name=FreeCAD.ActiveDocument.ActiveObject.Name
- myhole=addPadLong2(dcx, dcy, dx, dy, perc, tp, z_offset)
- if test_flag_pads==True:
+ FreeCAD.ActiveDocument.ActiveObject.Label = "myannular"
+ myhole = addPadLong2(dcx, dcy, dx, dy, perc, tp, z_offset)
+ if test_flag_pads:
Part.show(myhole)
- FreeCAD.ActiveDocument.ActiveObject.Label="myhole"
- #wire = [mypad,mydrill]
- wire = [mydrill]
- drl = Part.Face(wire)
- #Part.show(drl)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "myhole"
+ # wire = [mypad,mydrill]
+ wire = [mydrill]
+ drl = Part.Face(wire)
+ # Part.show(drl)
face = mypad.cut(drl)
- extr = face.extrude(FreeCAD.Vector(0,0,thick))
- #Part.show(extr);stop
- if test_flag_pads==True:
+ extr = face.extrude(FreeCAD.Vector(0, 0, thick))
+ # Part.show(extr);stop
+ if test_flag_pads:
Part.show(extr)
- FreeCAD.ActiveDocument.ActiveObject.Label="drilled_pad"
+ FreeCAD.ActiveDocument.ActiveObject.Label = "drilled_pad"
FreeCAD.ActiveDocument.removeObject(pad_name)
FreeCAD.ActiveDocument.recompute()
else:
face = Part.Face(mypad)
- extr = face.extrude(FreeCAD.Vector(0,0,thick))
- #Part.show(extr)
- #FreeCAD.ActiveDocument.ActiveObject.Label="smd_pad"
+ extr = face.extrude(FreeCAD.Vector(0, 0, thick))
+ # Part.show(extr)
+ # FreeCAD.ActiveDocument.ActiveObject.Label="smd_pad"
FreeCAD.ActiveDocument.removeObject(pad_name)
FreeCAD.ActiveDocument.recompute()
- #extr = sface.extrude(FreeCAD.Vector(0,0,-.01))
- #Part.show(extr)
- #stop
-
+ # extr = sface.extrude(FreeCAD.Vector(0,0,-.01))
+ # Part.show(extr)
+ # stop
+
return extr
-
+
+
###
-def createArcW (layer, content, arc_prim, layer_list):
+def createArcW(layer, content, arc_prim, layer_list):
fpArc = getArc(layer, content, arc_prim)
- #print(layer,fpArc)
+ # print(layer,fpArc)
for i in fpArc:
- if len(i) == 6: #kv5
- x1 = i[0] #+ X1
- y1 = i[1] #+ Y1
- x2 = i[2] #+ X1
- y2 = i[3] #+ Y1
+ if len(i) == 6: # kv5
+ x1 = i[0] # + X1
+ y1 = i[1] # + Y1
+ x2 = i[2] # + X1
+ y2 = i[3] # + Y1
_angle = i[4]
# print('center=',x1,y1,' end=',x2,y2,' angle=',i[4],' width=',i[5])
- arc1=addArc_3([x1, y1], [x2, y2], i[4], i[5])
+ arc1 = addArc_3([x1, y1], [x2, y2], i[4], i[5])
# kv5 fp_arc start=center coord, end=arc_end coord, angle=delta angle
# getArc -> [x2, y2] = rotPoint2([x1, y1], [xc, yc], curve)
- xm=(x1+x2)/2
- ym=(y1+y2)/2
+ xm = (x1 + x2) / 2
+ ym = (y1 + y2) / 2
rotateObj(arc1, [xm, ym, 180])
layer_list.append(arc1)
- elif len(i) == 7: #kv6
+ elif len(i) == 7: # kv6
# kv6 fp_arc start=arc_start coord, mid=arc_mid coord, end=arc_end coord
# start, mid, end
- xs = i[0]; ys = i[1] #+ Y1
- xm = i[2]; ym = i[3] #+ Y1
- xe = i[4]; ye = i[5] #+ Y1
- edge_arc = Part.ArcOfCircle(kicad_parser.makeVect([xs,-ys]),
- kicad_parser.makeVect([xm,-ym]),
- kicad_parser.makeVect([xe,-ye])).toShape()
- #Draft.makeSketch(edge_arc)
+ xs = i[0]
+ ys = i[1] # + Y1
+ xm = i[2]
+ ym = i[3] # + Y1
+ xe = i[4]
+ ye = i[5] # + Y1
+ edge_arc = Part.ArcOfCircle(
+ kicad_parser.makeVect([xs, -ys]),
+ kicad_parser.makeVect([xm, -ym]),
+ kicad_parser.makeVect([xe, -ye]),
+ ).toShape()
+ # Draft.makeSketch(edge_arc)
# e => arc Edge
- delta_angle=degrees(edge_arc.LastParameter-edge_arc.FirstParameter)
+ delta_angle = degrees(edge_arc.LastParameter - edge_arc.FirstParameter)
center = edge_arc.Curve.Center
- xc,yc,zc= center[0],center[1],center[2]
- #print (center); print(delta_angle)
+ _xc, _yc, _zc = center[0], center[1], center[2]
+ # print (center); print(delta_angle)
# arc1_kv5=addArc_3([x1, y1], [x2, y2], i[4], i[5])
# kv5 fp_arc start=center coord, end=arc_end coord, angle=delta angle
- [x1,y1] = [xe, ye]
- [x2,y2] = [xs,ys] #rotPoint2([x1, y1], [xs, ys], -curve)
+ [x1, y1] = [xe, ye]
+ [x2, y2] = [xs, ys] # rotPoint2([x1, y1], [xs, ys], -curve)
# if curve <0:
# curve*=-1
- #if curve >90:
+ # if curve >90:
# curve=(curve-90)/4
# arc1 = addArc_3([x1, y1], [x2, y2], curve, i[6])
arc1 = addArc_3([x1, y1], [x2, y2], delta_angle, i[6])
- #arc1 = addArc_3([center[0], -center[1]], [x2, y2], -curve+180/2, i[6])
- xm=(x1+x2)/2
- ym=(y1+y2)/2
- #rotateObj(arc1, [xm, ym, 180])
- #.rotate(Vector(),Vector(0,0,1),180)
+ # arc1 = addArc_3([center[0], -center[1]], [x2, y2], -curve+180/2, i[6])
+ xm = (x1 + x2) / 2
+ ym = (y1 + y2) / 2
+ # rotateObj(arc1, [xm, ym, 180])
+ # .rotate(Vector(),Vector(0,0,1),180)
layer_list.append(arc1)
- #else:
+ # else:
# print(len(i),str(i))
- #if mksketch:
+ # if mksketch:
# skt = Draft.makeSketch(arc1)
+
+
###
-def routineDrawFootPrint(content,name):
+def routineDrawFootPrint(content, name):
global rot_wrl, zfit
- #for item in content:
+ # for item in content:
# say(item)
# x1, y1, x2, y2, width
- say("FootPrint Loader "+name)
- footprint_name=getModName(content)
- rot_wrl=getwrlRot(content)
+ say("FootPrint Loader " + name)
+ footprint_name = getModName(content)
+ rot_wrl = getwrlRot(content)
posiz, scale, rot = getwrlData(content)
- #say(posiz);say(scale);say(rot);
- error_mod=False
- #if scale!=['1', '1', '1']:
- xsc_vrml_val=scale[0]
- ysc_vrml_val=scale[1]
- zsc_vrml_val=scale[2]
+ # say(posiz);say(scale);say(rot);
+ error_mod = False
+ # if scale!=['1', '1', '1']:
+ xsc_vrml_val = scale[0]
+ ysc_vrml_val = scale[1]
+ zsc_vrml_val = scale[2]
# if scale_vrml!='1 1 1':
- #sayw(scale)
- if float(xsc_vrml_val)!=1.0 or float(ysc_vrml_val)!=1.0 or float(zsc_vrml_val)!=1.0:
- sayw('wrong scale!!! set scale to (1 1 1)\n')
- error_mod=True
- if posiz!=['0', '0', '0']:
- sayw('wrong xyx position!!! set xyz to (0 0 0)\n')
- error_mod=True
- if rot[0]!='0' or rot[1]!='0':
- sayw('wrong rotation!!! set rotate x and y to (0 0 z)\n')
- error_mod=True
+ # sayw(scale)
+ if float(xsc_vrml_val) != 1.0 or float(ysc_vrml_val) != 1.0 or float(zsc_vrml_val) != 1.0:
+ sayw("wrong scale!!! set scale to (1 1 1)\n")
+ error_mod = True
+ if posiz != ["0", "0", "0"]:
+ sayw("wrong xyx position!!! set xyz to (0 0 0)\n")
+ error_mod = True
+ if rot[0] != "0" or rot[1] != "0":
+ sayw("wrong rotation!!! set rotate x and y to (0 0 z)\n")
+ error_mod = True
if error_mod:
- msg="""Error in '.kicad_mod' footprint
"""
- msg+="
reset values to:
"
- msg+="(at (xyz 0 0 0))
"
- msg+="(scale (xyz 1 1 1))
"
- msg+="(rotate (xyz 0 0 z))
"
- msg+="
Only z rotation is allowed!"
- reply = QtGui.QMessageBox.information(None,"info", msg)
- #stop
- #say(footprint_name+" wrl rotation:"+str(rot_wrl))
- if FreeCAD.activeDocument():
- doc=FreeCAD.activeDocument()
- else:
- doc=FreeCAD.newDocument()
- #doc.UndoMode = 1
- #doc.openTransaction()
- doc.openTransaction('opening_kicad_footprint')
- say('opening Transaction \'opening_kicad_footprint\'')
+ msg = """Error in '.kicad_mod' footprint
"""
+ msg += "
reset values to:
"
+ msg += "(at (xyz 0 0 0))
"
+ msg += "(scale (xyz 1 1 1))
"
+ msg += "(rotate (xyz 0 0 z))
"
+ msg += "
Only z rotation is allowed!"
+ QtGui.QMessageBox.information(None, "info", msg)
+ # stop
+ # say(footprint_name+" wrl rotation:"+str(rot_wrl))
+ doc = FreeCAD.activeDocument() if FreeCAD.activeDocument() else FreeCAD.newDocument()
+ # doc.UndoMode = 1
+ # doc.openTransaction()
+ doc.openTransaction("opening_kicad_footprint")
+ say("opening Transaction 'opening_kicad_footprint'")
for obj in FreeCAD.ActiveDocument.Objects:
FreeCADGui.Selection.removeSelection(obj)
- TopPadList=[]
- BotPadList=[]
- HoleList=[]
- THPList=[]
- TopNetTieList=[]
- BotNetTieList=[]
+ TopPadList = []
+ BotPadList = []
+ HoleList = []
+ THPList = []
+ TopNetTieList = []
+ BotNetTieList = []
for pad in getPadsList(content):
# sayerr(pad)
#
# pads.append({'x': x, 'y': y, 'rot': rot, 'padType': pType, 'padShape': pShape, 'rx': drill_x, 'ry': drill_y, 'dx': dx, 'dy': dy, 'holeType': hType, 'xOF': xOF, 'yOF': yOF, 'layers': layers})
- pType = pad['padType']
- pShape = pad['padShape']
- pRratio = pad['rratio']
- pGeomC = pad['geomC']
- xs = pad['x'] #+ X1
- ys = pad['y'] #+ Y1
- dx = pad['dx']
- dy = pad['dy']
- hType = pad['holeType']
- drill_x = pad['rx']
- drill_y = pad['ry']
- xOF = pad['xOF']
- yOF = pad['yOF']
- rot = pad['rot']
- rx=drill_x
- ry=drill_y
- numberOfLayers = pad['layers'].replace('"', '').split(' ') # fixing double quotes in layers & pads
+ pad["padType"]
+ pShape = pad["padShape"]
+ pRratio = pad["rratio"]
+ pGeomC = pad["geomC"]
+ xs = pad["x"] # + X1
+ ys = pad["y"] # + Y1
+ dx = pad["dx"]
+ dy = pad["dy"]
+ hType = pad["holeType"]
+ drill_x = pad["rx"]
+ drill_y = pad["ry"]
+ xOF = pad["xOF"]
+ yOF = pad["yOF"]
+ rot = pad["rot"]
+ rx = drill_x
+ ry = drill_y
+ numberOfLayers = pad["layers"].replace('"', "").split(" ") # fixing double quotes in layers & pads
# print(numberOfLayers)
# print('F.Cu' in numberOfLayers)
- pnts = pad['points']
- anchor = pad['anchor']
- #if pnts is not None:
+ pnts = pad["points"]
+ anchor = pad["anchor"]
+ # if pnts is not None:
# sayw(pnts.groups(0)[0].split('(xy'))
- #sayw(pnts)
- #say(str(rx))
- #say(numberOfLayers)
- #if pType=="thru_hole":
- #pad shape - circle/rec/oval/trapezoid
- perc=0
- if pShape=="circle" or pShape=="oval":
+ # sayw(pnts)
+ # say(str(rx))
+ # say(numberOfLayers)
+ # if pType=="thru_hole":
+ # pad shape - circle/rec/oval/trapezoid
+ if pShape in {"circle", "oval"}:
##pShape="oval"
- perc=100
+ pass
# pad type - SMD/thru_hole/connect
- #say(pType+"here")
- if dx>rx and dy>ry:
- #say(pType)
- #say(str(dx)+"+"+str(rx)+" dx,rx")
- #say(str(dy)+"+"+str(ry)+" dy,ry")
- #say(str(xOF)+"+"+str(yOF)+" xOF,yOF")
- #def addPadLong(x, y, dx, dy, perc, typ, z_off):
- #say(str(x1)+"+"+str(y1)+" x1,y1")
- top=False
- bot=False
- if 'F.Cu' in numberOfLayers:
- top=True
- if '*.Cu' in numberOfLayers:
- top=True
- bot=True
- if 'B.Cu' in numberOfLayers:
- bot=True
+ # say(pType+"here")
+ if dx > rx and dy > ry:
+ # say(pType)
+ # say(str(dx)+"+"+str(rx)+" dx,rx")
+ # say(str(dy)+"+"+str(ry)+" dy,ry")
+ # say(str(xOF)+"+"+str(yOF)+" xOF,yOF")
+ # def addPadLong(x, y, dx, dy, perc, typ, z_off):
+ # say(str(x1)+"+"+str(y1)+" x1,y1")
+ top = False
+ bot = False
+ if "F.Cu" in numberOfLayers:
+ top = True
+ if "*.Cu" in numberOfLayers:
+ top = True
+ bot = True
+ if "B.Cu" in numberOfLayers:
+ bot = True
# print(numberOfLayers)
- pattern = 'In+([0-9]*?).Cu'
+ pattern = "In+([0-9]*?).Cu"
result = re.search(pattern, str(numberOfLayers))
if result is not None:
- sayerr('internal layers not supported!')
+ sayerr("internal layers not supported!")
sayw(result.group())
- if top==True:
- x1=xs+xOF
- y1=ys-yOF #yoffset opposite
- #mypad=addPadLong(x1, y1, dx, dy, perc, 0, 0)
+ if top:
+ x1 = xs + xOF
+ y1 = ys - yOF # yoffset opposite
+ # mypad=addPadLong(x1, y1, dx, dy, perc, 0, 0)
mypad2 = None
skip = False
- if pShape=='custom' and pGeomC is None:
- #if (pShape=='custom' or pShape=='NetTie') and pGeomC is None:
- #sayw(pnts.groups(0)[0].split('(xy'))
- #print(pGeomC)
+ if pShape == "custom" and pGeomC is None:
+ # if (pShape=='custom' or pShape=='NetTie') and pGeomC is None:
+ # sayw(pnts.groups(0)[0].split('(xy'))
+ # print(pGeomC)
try:
- poly_points=pnts.groups(0)[0].split('(xy')[1:]
- mypad=createPoly(x1, y1, dx, dy, xs,ys,rx,ry,pShape,'top', poly_points)
+ poly_points = pnts.groups(0)[0].split("(xy")[1:]
+ mypad = createPoly(x1, y1, dx, dy, xs, ys, rx, ry, pShape, "top", poly_points)
if anchor is not None:
- if anchor[0]=="circle":
- perc=100
- #print 'anchor ',anchor[0]
- mypad2=createPad3(x1, y1, dx, dy, xs,ys,rx,ry,anchor,'top')
- #Part.show(mypad2)
- #print anchor
- #stop
+ if anchor[0] == "circle":
+ pass
+ # print 'anchor ',anchor[0]
+ mypad2 = createPad3(x1, y1, dx, dy, xs, ys, rx, ry, anchor, "top")
+ # Part.show(mypad2)
+ # print anchor
+ # stop
except:
- sayerr('geometry unsupported')
+ sayerr("geometry unsupported")
skip = True
- elif pShape=='custom' and pGeomC is not None:
- #sayerr(pGeomC)
- #print('pGeomC',(pGeomC))
- #print ('x1',x1,'y1',y1)
- Gc=pGeomC[0].split(' ')
- #Gcx=-float(Gc[1])-x1;Gcy=float(Gc[2])-y1
- Gr=pGeomC[1].split(' ')
- GRad=abs(float(Gr[1])-float(Gc[1]))
- Gcx=x1+float(Gc[1])
- Gcy=float(Gc[2])-y1
- #print('Gr',Gr,'GR',GRad,'Gc1',Gc[1],'Gc2',Gc[2],'Gcx',Gcx)
- Gw=pGeomC[2].split(' ')
- Gw=float(Gw[1])
- #print (Gcx,Gcy,GRad,Gw)
- mypad=createGeomC(Gcx, Gcy, GRad,'top', Gw)
+ elif pShape == "custom" and pGeomC is not None:
+ # sayerr(pGeomC)
+ # print('pGeomC',(pGeomC))
+ # print ('x1',x1,'y1',y1)
+ Gc = pGeomC[0].split(" ")
+ # Gcx=-float(Gc[1])-x1;Gcy=float(Gc[2])-y1
+ Gr = pGeomC[1].split(" ")
+ GRad = abs(float(Gr[1]) - float(Gc[1]))
+ Gcx = x1 + float(Gc[1])
+ Gcy = float(Gc[2]) - y1
+ # print('Gr',Gr,'GR',GRad,'Gc1',Gc[1],'Gc2',Gc[2],'Gcx',Gcx)
+ Gw = pGeomC[2].split(" ")
+ Gw = float(Gw[1])
+ # print (Gcx,Gcy,GRad,Gw)
+ mypad = createGeomC(Gcx, Gcy, GRad, "top", Gw)
if anchor is not None:
- if anchor[0]=="circle":
- perc=100
- #print 'anchor ',anchor[0]
- mypad2=createPad3(x1, y1, dx, dy, xs,ys,rx,ry,anchor,'top')
- #Part.show(mypad2)
-
- #print TopPadList
- #stop
+ if anchor[0] == "circle":
+ pass
+ # print 'anchor ',anchor[0]
+ mypad2 = createPad3(x1, y1, dx, dy, xs, ys, rx, ry, anchor, "top")
+ # Part.show(mypad2)
+
+ # print TopPadList
+ # stop
else:
- #mypad=createPad3(x1, y1, dx, dy, xs,ys,rx,ry,pShape,'top')
- mypad=createPad3(x1, y1, dx, dy, xs,ys,rx,ry,pShape,'top',pRratio)
+ # mypad=createPad3(x1, y1, dx, dy, xs,ys,rx,ry,pShape,'top')
+ mypad = createPad3(x1, y1, dx, dy, xs, ys, rx, ry, pShape, "top", pRratio)
##pad pos x,y; pad size x,y; drillcenter x,y; drill size x,y, layer
- obj=mypad
+ obj = mypad
if rot != 0 and not skip:
rotateObj(obj, [xs, ys, rot])
if mypad2 is not None:
@@ -10509,83 +11351,83 @@ def routineDrawFootPrint(content,name):
TopPadList.append(obj)
if mypad2 is not None:
TopPadList.append(mypad2)
-
- if bot==True:
- #on Bot layer offset is opposite
- x1=xs-xOF
- y1=ys+yOF #yoffset opposite
- #mypad=addPadLong(x1, y1, dx, dy, perc, 0, -1.6)
- mypad2=None; skip = False
- #if pShape=='custom':
- if pShape=='custom' and pGeomC is None:
- #sayw(pnts.groups(0)[0].split('(xy'))
+
+ if bot:
+ # on Bot layer offset is opposite
+ x1 = xs - xOF
+ y1 = ys + yOF # yoffset opposite
+ # mypad=addPadLong(x1, y1, dx, dy, perc, 0, -1.6)
+ mypad2 = None
+ skip = False
+ # if pShape=='custom':
+ if pShape == "custom" and pGeomC is None:
+ # sayw(pnts.groups(0)[0].split('(xy'))
try:
- poly_points=pnts.groups(0)[0].split('(xy')[1:]
- mypad=createPoly(x1, y1, dx, dy, xs,ys,rx,ry,pShape,'bot', poly_points)
+ poly_points = pnts.groups(0)[0].split("(xy")[1:]
+ mypad = createPoly(x1, y1, dx, dy, xs, ys, rx, ry, pShape, "bot", poly_points)
if anchor is not None:
- if anchor=="circle":
- perc=100
- mypad2=createPad3(x1, y1, dx, dy, xs,ys,rx,ry,anchor,'bot')
+ if anchor == "circle":
+ pass
+ mypad2 = createPad3(x1, y1, dx, dy, xs, ys, rx, ry, anchor, "bot")
except:
- sayerr('geometry unsupported')
+ sayerr("geometry unsupported")
skip = True
- elif pShape=='custom' and pGeomC is not None:
- #sayerr(pGeomC)
- #print('pGeomC',(pGeomC))
- #print ('x1',x1,'y1',y1)
- Gc=pGeomC[0].split(' ')
- #Gcx=-float(Gc[1])-x1;Gcy=float(Gc[2])-y1
- Gr=pGeomC[1].split(' ')
- GRad=abs(float(Gr[1])-float(Gc[1]))
- Gcx=x1+float(Gc[1])
- Gcy=float(Gc[2])-y1
- #print('Gr',Gr,'GR',GRad,'Gc1',Gc[1],'Gc2',Gc[2],'Gcx',Gcx)
- Gw=pGeomC[2].split(' ')
- Gw=float(Gw[1])
- #print (Gcx,Gcy,GRad,Gw)
- mypad=createGeomC(Gcx, Gcy, GRad,'bot', Gw)
+ elif pShape == "custom" and pGeomC is not None:
+ # sayerr(pGeomC)
+ # print('pGeomC',(pGeomC))
+ # print ('x1',x1,'y1',y1)
+ Gc = pGeomC[0].split(" ")
+ # Gcx=-float(Gc[1])-x1;Gcy=float(Gc[2])-y1
+ Gr = pGeomC[1].split(" ")
+ GRad = abs(float(Gr[1]) - float(Gc[1]))
+ Gcx = x1 + float(Gc[1])
+ Gcy = float(Gc[2]) - y1
+ # print('Gr',Gr,'GR',GRad,'Gc1',Gc[1],'Gc2',Gc[2],'Gcx',Gcx)
+ Gw = pGeomC[2].split(" ")
+ Gw = float(Gw[1])
+ # print (Gcx,Gcy,GRad,Gw)
+ mypad = createGeomC(Gcx, Gcy, GRad, "bot", Gw)
if anchor is not None:
- if anchor[0]=="circle":
- perc=100
- #print 'anchor ',anchor[0]
- mypad2=createPad3(x1, y1, dx, dy, xs,ys,rx,ry,anchor,'bot')
+ if anchor[0] == "circle":
+ pass
+ # print 'anchor ',anchor[0]
+ mypad2 = createPad3(x1, y1, dx, dy, xs, ys, rx, ry, anchor, "bot")
Part.show(mypad2)
- #stop
+ # stop
else:
- mypad=createPad3(x1, y1, dx, dy, xs,ys,rx,ry,pShape,'bot',pRratio)
+ mypad = createPad3(x1, y1, dx, dy, xs, ys, rx, ry, pShape, "bot", pRratio)
##pad pos x,y; pad size x,y; drillcenter x,y; drill size x,y, layerobj=mypad
- obj=mypad
- if rot!=0 and not skip:
- rotateObj(obj, [xs, ys, +rot+180])
- #rotateObj(obj, [xs, ys, -rot+180])
+ obj = mypad
+ if rot != 0 and not skip:
+ rotateObj(obj, [xs, ys, +rot + 180])
+ # rotateObj(obj, [xs, ys, -rot+180])
if mypad2 is not None:
- rotateObj(mypad2, [xs, ys, +rot+180])
- #rotateObj(mypad2, [xs, ys, -rot+180])
+ rotateObj(mypad2, [xs, ys, +rot + 180])
+ # rotateObj(mypad2, [xs, ys, -rot+180])
if not skip:
BotPadList.append(obj)
if mypad2 is not None:
BotPadList.append(mypad2)
- if rx!=0:
- #obj=createHole2(xs,ys,rx,ry,"oval") #need to be separated instructions
- #print pShape
- #stop
- hole_tp=hType.strip()
- #sayw(hole_tp)
- obj=createHole2(xs,ys,rx,ry,hole_tp) #need to be separated instructions
+ if rx != 0:
+ # obj=createHole2(xs,ys,rx,ry,"oval") #need to be separated instructions
+ # print pShape
+ # stop
+ hole_tp = hType.strip()
+ # sayw(hole_tp)
+ obj = createHole2(xs, ys, rx, ry, hole_tp) # need to be separated instructions
##obj=createHole2(xs,ys,rx,ry,pShape) #need to be separated instructions
- #say(HoleList)
- if rot!=0:
+ # say(HoleList)
+ if rot != 0:
rotateObj(obj, [xs, ys, rot])
HoleList.append(obj)
- #obj2=createTHPlate(xs,ys,rx,ry,"oval")
- obj2=createTHPlate(xs,ys,rx,ry,hole_tp)
+ # obj2=createTHPlate(xs,ys,rx,ry,"oval")
+ obj2 = createTHPlate(xs, ys, rx, ry, hole_tp)
##obj2=createTHPlate(xs,ys,rx,ry,pShape)
THPList.append(obj2)
- if rot!=0:
+ if rot != 0:
rotateObj(obj2, [xs, ys, rot])
-
- #say(pType+"here")
+ # say(pType+"here")
### cmt- #da gestire: pad type trapez
FrontSilk = []
FCrtYd = []
@@ -10594,480 +11436,466 @@ def routineDrawFootPrint(content,name):
BotSilk = []
BCrtYd = []
BFab = []
-
- layer_names = ['F.SilkS','F.CrtYd','F.Fab','Edge.Cuts','B.SilkS','B.CrtYd','B.Fab']
- layers_name_list = [FrontSilk,FCrtYd,FFab,EdgeCuts,BotSilk,BCrtYd,BFab]
-
- fp_list,width = getPolyList(content)
+
+ layer_names = ["F.SilkS", "F.CrtYd", "F.Fab", "Edge.Cuts", "B.SilkS", "B.CrtYd", "B.Fab"]
+ layers_name_list = [FrontSilk, FCrtYd, FFab, EdgeCuts, BotSilk, BCrtYd, BFab]
+
+ fp_list, width = getPolyList(content)
for fp in fp_list:
- pnts = fp['points']
- layers = fp['layers']
- #print(layers)
- pShape = 'NetTie'
+ pnts = fp["points"]
+ layers = fp["layers"]
+ # print(layers)
+ pShape = "NetTie"
skip = False
- if 'B.Cu' in layers or 'B.Mask' in layers:
- lyr = 'bot'
- elif 'F.Cu' in layers:
- lyr = 'top'
- elif 'Edge.Cuts' in layers:
- lyr = 'Edge.Cuts'
+ if "B.Cu" in layers or "B.Mask" in layers:
+ lyr = "bot"
+ elif "F.Cu" in layers:
+ lyr = "top"
+ elif "Edge.Cuts" in layers:
+ lyr = "Edge.Cuts"
else:
lyr = None
- sayw('geometry unsupported')
- if pnts is not None and lyr is not None and lyr != 'Edge.Cuts': # minimal closed shape points
- #sayw(pnts.groups(0)[0].split('(xy'))
- #print(pGeomC)
+ sayw("geometry unsupported")
+ if pnts is not None and lyr is not None and lyr != "Edge.Cuts": # minimal closed shape points
+ # sayw(pnts.groups(0)[0].split('(xy'))
+ # print(pGeomC)
try:
- poly_points=pnts.groups(0)[0].split('(xy')[1:]
- #print(poly_points)
- mypad=createPoly(0.0, 0.0, 0.0, 0.0, 0.0,0.0,0.0,0.0,pShape,lyr, poly_points)
+ poly_points = pnts.groups(0)[0].split("(xy")[1:]
+ # print(poly_points)
+ mypad = createPoly(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, pShape, lyr, poly_points)
except:
- sayerr('geometry unsupported')
+ sayerr("geometry unsupported")
skip = True
if not skip:
- if lyr == 'top':
- #TopPadList.append(mypad)
+ if lyr == "top":
+ # TopPadList.append(mypad)
TopNetTieList.append(mypad)
else:
- #BotPadList.append(mypad)
+ # BotPadList.append(mypad)
BotNetTieList.append(mypad)
# polyline fp_poly
- elif lyr == 'Edge.Cuts':
- #print(pnts.groups(0)[1])
- poly_points=pnts.groups(0)[1].split('(xy')[1:]
- #print(poly_points)
- for i,p in enumerate (poly_points[:-1]):
- p=p[1:].split(')')[0].split(' ')
- p1 = poly_points[i+1][1:].split(')')[0].split(' ')
- x1 = float(p[0]) #+ X1
- y1 = -float(p[1]) #+ Y1
- x2 = float(p1[0]) #+ X1
- y2 = -float(p1[1]) #+ Y1
+ elif lyr == "Edge.Cuts":
+ # print(pnts.groups(0)[1])
+ poly_points = pnts.groups(0)[1].split("(xy")[1:]
+ # print(poly_points)
+ for i, p in enumerate(poly_points[:-1]):
+ p = p[1:].split(")")[0].split(" ")
+ p1 = poly_points[i + 1][1:].split(")")[0].split(" ")
+ x1 = float(p[0]) # + X1
+ y1 = -float(p[1]) # + Y1
+ x2 = float(p1[0]) # + X1
+ y2 = -float(p1[1]) # + Y1
obj = addLine_2(x1, y1, x2, y2, 0.12)
layers_name_list[3].append(addLine_2(x1, y1, x2, y2, width))
- #closing poly
- p = poly_points[0][1:].split(')')[0].split(' ')
- x1 = float(p[0]) #+ X1
- y1 = -float(p[1]) #+ Y1
+ # closing poly
+ p = poly_points[0][1:].split(")")[0].split(" ")
+ x1 = float(p[0]) # + X1
+ y1 = -float(p[1]) # + Y1
obj = addLine_2(x2, y2, x1, y1, width)
layers_name_list[3].append(addLine_2(x1, y1, x2, y2, width))
- #stop
-
-##
+ # stop
+
+ ##
- #FrontSilk = []
- #FCrtYd = []
- #FFab = []
- #EdgeCuts = []
- #BotSilk = []
- #BCrtYd = []
- #BFab = []
+ # FrontSilk = []
+ # FCrtYd = []
+ # FFab = []
+ # EdgeCuts = []
+ # BotSilk = []
+ # BCrtYd = []
+ # BFab = []
#
- #layer_names = ['F.SilkS','F.CrtYd','F.Fab','Edge.Cuts','B.SilkS','B.CrtYd','B.Fab']
- #layers_name_list = [FrontSilk,FCrtYd,FFab,EdgeCuts,BotSilk,BCrtYd,BFab]
-
- #TBD
- #for n,lay in enumerate (layer_names):
+ # layer_names = ['F.SilkS','F.CrtYd','F.Fab','Edge.Cuts','B.SilkS','B.CrtYd','B.Fab']
+ # layers_name_list = [FrontSilk,FCrtYd,FFab,EdgeCuts,BotSilk,BCrtYd,BFab]
+
+ # TBD
+ # for n,lay in enumerate (layer_names):
# getPolyList
-
+
# line
- #getLine('F.SilkS', content, 'fp_line')
- for n,lay in enumerate (layer_names):
- for i in getLine(lay, content, 'fp_line'):
- x1 = i[0] #+ X1
- y1 = i[1] #+ Y1
- x2 = i[2] #+ X1
- y2 = i[3] #+ Y1
+ # getLine('F.SilkS', content, 'fp_line')
+ for n, lay in enumerate(layer_names):
+ for i in getLine(lay, content, "fp_line"):
+ x1 = i[0] # + X1
+ y1 = i[1] # + Y1
+ x2 = i[2] # + X1
+ y2 = i[3] # + Y1
obj = addLine_2(x1, y1, x2, y2, i[4])
layers_name_list[n].append(addLine_2(x1, y1, x2, y2, i[4]))
- for n,lay in enumerate (layer_names):
- for i in getLine(lay, content, 'fp_rect'):
- x1 = i[0] #+ X1
- y1 = i[1] #+ Y1
- x2 = i[2] #+ X1
- y2 = i[3] #+ Y1
+ for n, lay in enumerate(layer_names):
+ for i in getLine(lay, content, "fp_rect"):
+ x1 = i[0] # + X1
+ y1 = i[1] # + Y1
+ x2 = i[2] # + X1
+ y2 = i[3] # + Y1
obj = addLine_2(x1, y1, x2, y2, i[4])
layers_name_list[n].append(addLine_2(x1, y1, x2, y1, i[4]))
layers_name_list[n].append(addLine_2(x2, y1, x2, y2, i[4]))
layers_name_list[n].append(addLine_2(x2, y2, x1, y2, i[4]))
layers_name_list[n].append(addLine_2(x1, y2, x1, y1, i[4]))
-
+
# circle
- for n,lay in enumerate (layer_names):
- for i in getCircle(lay, content, 'fp_circle'):
- xs = i[0] #+ X1
- ys = i[1] #+ Y1
+ for n, lay in enumerate(layer_names):
+ for i in getCircle(lay, content, "fp_circle"):
+ xs = i[0] # + X1
+ ys = i[1] # + Y1
layers_name_list[n].append(addCircle_2(xs, ys, i[2], i[3]))
# arc
- for n,lay in enumerate (layer_names):
+ for n, lay in enumerate(layer_names):
# print(l,lay,content)
- arc1 = createArcW (lay, content, 'fp_arc', layers_name_list[n])
-
- if len(FCrtYd)>0:
- #FSilk_lines = Part.makeCompound(FrontSilk)
- #Part.show(FSilk_lines)
- FCrtYd_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","FCrtYd_lines")
- #FSilk_lines.Label="FSilk_lines"
- #FSilk_lines_name=FSilk_lines.Name
- FCrtYd_lines.addProperty("App::PropertyBool","fixedPosition","importPart")
- FCrtYd_lines.Shape = Part.makeCompound(FCrtYd) #TopPadsBase.Shape.copy()
- FCrtYd_lines.ViewObject.Proxy=0
+ createArcW(lay, content, "fp_arc", layers_name_list[n])
+
+ if len(FCrtYd) > 0:
+ # FSilk_lines = Part.makeCompound(FrontSilk)
+ # Part.show(FSilk_lines)
+ FCrtYd_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "FCrtYd_lines")
+ # FSilk_lines.Label="FSilk_lines"
+ # FSilk_lines_name=FSilk_lines.Name
+ FCrtYd_lines.addProperty("App::PropertyBool", "fixedPosition", "importPart")
+ FCrtYd_lines.Shape = Part.makeCompound(FCrtYd) # TopPadsBase.Shape.copy()
+ FCrtYd_lines.ViewObject.Proxy = 0
FCrtYd_lines.fixedPosition = True
- FreeCAD.ActiveDocument.ActiveObject.Label="FCrtYd"
- FCrtYd_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.0000,0.0000,1.0000)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "FCrtYd"
+ FCrtYd_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.0000, 0.0000, 1.0000)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
- #
- if len(BCrtYd)>0:
- BCrtYd_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","BCrtYd_lines")
- BCrtYd_lines.addProperty("App::PropertyBool","fixedPosition","importPart")
- BCrtYd_lines.Shape = Part.makeCompound(BCrtYd) #TopPadsBase.Shape.copy()
- BCrtYd_lines.ViewObject.Proxy=0
+ if len(BCrtYd) > 0:
+ BCrtYd_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "BCrtYd_lines")
+ BCrtYd_lines.addProperty("App::PropertyBool", "fixedPosition", "importPart")
+ BCrtYd_lines.Shape = Part.makeCompound(BCrtYd) # TopPadsBase.Shape.copy()
+ BCrtYd_lines.ViewObject.Proxy = 0
BCrtYd_lines.fixedPosition = True
- FreeCAD.ActiveDocument.ActiveObject.Label="BCrtYd"
- BCrtYd_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.0000,0.0000,1.0000)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "BCrtYd"
+ BCrtYd_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.0000, 0.0000, 1.0000)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
- FreeCAD.ActiveDocument.ActiveObject.Placement.Base.z-=1.6
- #
- if len(FFab)>0:
- #FSilk_lines = Part.makeCompound(FrontSilk)
- #Part.show(FSilk_lines)
- FFab_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","FFab_lines")
- #FSilk_lines.Label="FSilk_lines"
- #FSilk_lines_name=FSilk_lines.Name
- FFab_lines.addProperty("App::PropertyBool","fixedPosition","importPart")
- FFab_lines.Shape = Part.makeCompound(FFab) #TopPadsBase.Shape.copy()
- FFab_lines.ViewObject.Proxy=0
+ FreeCAD.ActiveDocument.ActiveObject.Placement.Base.z -= 1.6
+ if len(FFab) > 0:
+ # FSilk_lines = Part.makeCompound(FrontSilk)
+ # Part.show(FSilk_lines)
+ FFab_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "FFab_lines")
+ # FSilk_lines.Label="FSilk_lines"
+ # FSilk_lines_name=FSilk_lines.Name
+ FFab_lines.addProperty("App::PropertyBool", "fixedPosition", "importPart")
+ FFab_lines.Shape = Part.makeCompound(FFab) # TopPadsBase.Shape.copy()
+ FFab_lines.ViewObject.Proxy = 0
FFab_lines.fixedPosition = True
- FreeCAD.ActiveDocument.ActiveObject.Label="FFab"
- FFab_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.0000,1.0000,0.0000)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "FFab"
+ FFab_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.0000, 1.0000, 0.0000)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
- #
- if len(BFab)>0:
- BFab_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","BFab_lines")
- BFab_lines.addProperty("App::PropertyBool","fixedPosition","importPart")
- BFab_lines.Shape = Part.makeCompound(BFab) #TopPadsBase.Shape.copy()
- BFab_lines.ViewObject.Proxy=0
+ if len(BFab) > 0:
+ BFab_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "BFab_lines")
+ BFab_lines.addProperty("App::PropertyBool", "fixedPosition", "importPart")
+ BFab_lines.Shape = Part.makeCompound(BFab) # TopPadsBase.Shape.copy()
+ BFab_lines.ViewObject.Proxy = 0
BFab_lines.fixedPosition = True
- FreeCAD.ActiveDocument.ActiveObject.Label="BFab"
- FFab_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.0000,1.0000,0.0000)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "BFab"
+ FFab_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.0000, 1.0000, 0.0000)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
- FreeCAD.ActiveDocument.ActiveObject.Placement.Base.z-=1.6
- #
- if len(FrontSilk)>0:
- #FSilk_lines = Part.makeCompound(FrontSilk)
- #Part.show(FSilk_lines)
- FSilk_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","FSilk_lines")
- #FSilk_lines.Label="FSilk_lines"
- #FSilk_lines_name=FSilk_lines.Name
- FSilk_lines.addProperty("App::PropertyBool","fixedPosition","importPart")
- FSilk_lines.Shape = Part.makeCompound(FrontSilk) #TopPadsBase.Shape.copy()
- FSilk_lines.ViewObject.Proxy=0
+ FreeCAD.ActiveDocument.ActiveObject.Placement.Base.z -= 1.6
+ if len(FrontSilk) > 0:
+ # FSilk_lines = Part.makeCompound(FrontSilk)
+ # Part.show(FSilk_lines)
+ FSilk_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "FSilk_lines")
+ # FSilk_lines.Label="FSilk_lines"
+ # FSilk_lines_name=FSilk_lines.Name
+ FSilk_lines.addProperty("App::PropertyBool", "fixedPosition", "importPart")
+ FSilk_lines.Shape = Part.makeCompound(FrontSilk) # TopPadsBase.Shape.copy()
+ FSilk_lines.ViewObject.Proxy = 0
FSilk_lines.fixedPosition = True
- FreeCAD.ActiveDocument.ActiveObject.Label="FrontSilk"
- FSilk_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (1.0000,1.0000,1.0000)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "FrontSilk"
+ FSilk_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (1.0000, 1.0000, 1.0000)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
- #
- if len(BotSilk)>0:
- #FSilk_lines = Part.makeCompound(FrontSilk)
- #Part.show(FSilk_lines)
- BSilk_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","BSilk_lines")
- #FSilk_lines.Label="FSilk_lines"
- #FSilk_lines_name=FSilk_lines.Name
- BSilk_lines.addProperty("App::PropertyBool","fixedPosition","importPart")
- BSilk_lines.Shape = Part.makeCompound(BotSilk) #TopPadsBase.Shape.copy()
- BSilk_lines.ViewObject.Proxy=0
+ if len(BotSilk) > 0:
+ # FSilk_lines = Part.makeCompound(FrontSilk)
+ # Part.show(FSilk_lines)
+ BSilk_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "BSilk_lines")
+ # FSilk_lines.Label="FSilk_lines"
+ # FSilk_lines_name=FSilk_lines.Name
+ BSilk_lines.addProperty("App::PropertyBool", "fixedPosition", "importPart")
+ BSilk_lines.Shape = Part.makeCompound(BotSilk) # TopPadsBase.Shape.copy()
+ BSilk_lines.ViewObject.Proxy = 0
BSilk_lines.fixedPosition = True
- FreeCAD.ActiveDocument.ActiveObject.Label="BotSilk"
- BSilk_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (1.0000,1.0000,1.0000)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "BotSilk"
+ BSilk_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (1.0000, 1.0000, 1.0000)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
- FreeCAD.ActiveDocument.ActiveObject.Placement.Base.z-=1.6
- #
- if len(EdgeCuts)>0:
- #FSilk_lines = Part.makeCompound(FrontSilk)
- #Part.show(FSilk_lines)
- ECuts_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","EdgeCuts_lines")
- #FSilk_lines.Label="FSilk_lines"
- #FSilk_lines_name=FSilk_lines.Name
- ECuts_lines.addProperty("App::PropertyBool","fixedPosition","importPart")
- ECuts_lines.Shape = Part.makeCompound(EdgeCuts) #TopPadsBase.Shape.copy()
- ECuts_lines.ViewObject.Proxy=0
+ FreeCAD.ActiveDocument.ActiveObject.Placement.Base.z -= 1.6
+ if len(EdgeCuts) > 0:
+ # FSilk_lines = Part.makeCompound(FrontSilk)
+ # Part.show(FSilk_lines)
+ ECuts_lines = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "EdgeCuts_lines")
+ # FSilk_lines.Label="FSilk_lines"
+ # FSilk_lines_name=FSilk_lines.Name
+ ECuts_lines.addProperty("App::PropertyBool", "fixedPosition", "importPart")
+ ECuts_lines.Shape = Part.makeCompound(EdgeCuts) # TopPadsBase.Shape.copy()
+ ECuts_lines.ViewObject.Proxy = 0
ECuts_lines.fixedPosition = True
- FreeCAD.ActiveDocument.ActiveObject.Label="EdgeCuts"
- ECuts_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (1.0000,0.0000,0.0000)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "EdgeCuts"
+ ECuts_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (1.0000, 0.0000, 0.0000)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 30
- #
- if len(TopPadList)>0:
+ if len(TopPadList) > 0:
# TopPadsBase = Part.makeCompound(TopPadList)
# Part.show(TopPadsBase)
# FreeCAD.ActiveDocument.ActiveObject.Label="TopPadsBase"
# TopPadsBase_name=FreeCAD.ActiveDocument.ActiveObject.Name
- TopPads = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","TopPads")
- TopPads.Label="TopPads"
- TopPads_name=TopPads.Name
- TopPads.addProperty("App::PropertyBool","fixedPosition","importPart")
- TopPads.Shape = Part.makeCompound(TopPadList) #TopPadsBase.Shape.copy()
- TopPads.ViewObject.Proxy=0
+ TopPads = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "TopPads")
+ TopPads.Label = "TopPads"
+ TopPads_name = TopPads.Name
+ TopPads.addProperty("App::PropertyBool", "fixedPosition", "importPart")
+ TopPads.Shape = Part.makeCompound(TopPadList) # TopPadsBase.Shape.copy()
+ TopPads.ViewObject.Proxy = 0
TopPads.fixedPosition = True
- #fp_group.addObject(TopPads)
- #FreeCAD.ActiveDocument.removeObject(TopPadsBase.Name)
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81,0.71,0.23) #(0.85,0.53,0.10)
+ # fp_group.addObject(TopPads)
+ # FreeCAD.ActiveDocument.removeObject(TopPadsBase.Name)
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81, 0.71, 0.23) # (0.85,0.53,0.10)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
- if len(BotPadList)>0:
- #BotPads = Part.makeCompound(BotPadList)
- #Part.show(BotPads)
- BotPads = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","BotPads")
- #BotPads.Label="BotPads"
- BotPads_name=BotPads.Name
- BotPads.addProperty("App::PropertyBool","fixedPosition","importPart")
- BotPads.Shape = Part.makeCompound(BotPadList) #TopPadsBase.Shape.copy()
- BotPads.ViewObject.Proxy=0
+ if len(BotPadList) > 0:
+ # BotPads = Part.makeCompound(BotPadList)
+ # Part.show(BotPads)
+ BotPads = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "BotPads")
+ # BotPads.Label="BotPads"
+ BotPads_name = BotPads.Name
+ BotPads.addProperty("App::PropertyBool", "fixedPosition", "importPart")
+ BotPads.Shape = Part.makeCompound(BotPadList) # TopPadsBase.Shape.copy()
+ BotPads.ViewObject.Proxy = 0
BotPads.fixedPosition = True
- FreeCAD.ActiveDocument.ActiveObject.Label="BotPads"
- BotPads_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81,0.71,0.23) #(0.85,0.53,0.10)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "BotPads"
+ BotPads_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81, 0.71, 0.23) # (0.85,0.53,0.10)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
-#
- if len(TopNetTieList)>0:
- TopNetTie = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","TopNetTie")
- TopNetTie.Label="TopNetTie"
- TopNetTie_name=TopNetTie.Name
- TopNetTie.addProperty("App::PropertyBool","fixedPosition","importPart")
- TopNetTie.Shape = Part.makeCompound(TopNetTieList) #TopPadsBase.Shape.copy()
- TopNetTie.ViewObject.Proxy=0
+ if len(TopNetTieList) > 0:
+ TopNetTie = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "TopNetTie")
+ TopNetTie.Label = "TopNetTie"
+ TopNetTie_name = TopNetTie.Name
+ TopNetTie.addProperty("App::PropertyBool", "fixedPosition", "importPart")
+ TopNetTie.Shape = Part.makeCompound(TopNetTieList) # TopPadsBase.Shape.copy()
+ TopNetTie.ViewObject.Proxy = 0
TopNetTie.fixedPosition = True
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81,0.71,0.23) #(0.85,0.53,0.10)
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81, 0.71, 0.23) # (0.85,0.53,0.10)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
- if len(BotNetTieList)>0:
- BotNetTie = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","BotNetTie")
- BotNetTie.Label="BotNetTie"
- BotNetTie_name=BotNetTie.Name
- BotNetTie.addProperty("App::PropertyBool","fixedPosition","importPart")
- BotNetTie.Shape = Part.makeCompound(BotNetTieList) #TopPadsBase.Shape.copy()
- BotNetTie.ViewObject.Proxy=0
+ if len(BotNetTieList) > 0:
+ BotNetTie = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "BotNetTie")
+ BotNetTie.Label = "BotNetTie"
+ BotNetTie_name = BotNetTie.Name
+ BotNetTie.addProperty("App::PropertyBool", "fixedPosition", "importPart")
+ BotNetTie.Shape = Part.makeCompound(BotNetTieList) # TopPadsBase.Shape.copy()
+ BotNetTie.ViewObject.Proxy = 0
BotNetTie.fixedPosition = True
- FreeCAD.ActiveDocument.ActiveObject.Label="BotNetTie"
- BotNetTie_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81,0.71,0.23) #(0.85,0.53,0.10)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "BotNetTie"
+ BotNetTie_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.81, 0.71, 0.23) # (0.85,0.53,0.10)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60
- #
- if len(HoleList)>0:
+ if len(HoleList) > 0:
Holes = Part.makeCompound(HoleList)
Holes = Part.makeSolid(Holes)
Part.show(Holes)
- #say(FreeCAD.ActiveDocument.ActiveObject.Name)
- FreeCAD.ActiveDocument.ActiveObject.Label="Holes"
- Holes_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #say(Holes_name)
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.67,1.00,0.50)
+ # say(FreeCAD.ActiveDocument.ActiveObject.Name)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "Holes"
+ Holes_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ # say(Holes_name)
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.67, 1.00, 0.50)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 70
- #THPs = Part.makeCompound(THPList)
- #THPs = Part.makeSolid(THPs) ##evaluate solid
- #Part.show(THPs)
- THPs = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","THPs")
- #THPs.Label="THPs"
- THPs_name=THPs.Name
- THPs.addProperty("App::PropertyBool","fixedPosition","importPart")
- THPs.Shape = Part.makeCompound(THPList) #TopPadsBase.Shape.copy()
- #THPs = Part.makeSolid(THPs)
- THPs.ViewObject.Proxy=0
+ # THPs = Part.makeCompound(THPList)
+ # THPs = Part.makeSolid(THPs) ##evaluate solid
+ # Part.show(THPs)
+ THPs = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "THPs")
+ # THPs.Label="THPs"
+ THPs_name = THPs.Name
+ THPs.addProperty("App::PropertyBool", "fixedPosition", "importPart")
+ THPs.Shape = Part.makeCompound(THPList) # TopPadsBase.Shape.copy()
+ # THPs = Part.makeSolid(THPs)
+ THPs.ViewObject.Proxy = 0
THPs.fixedPosition = True
- #say(FreeCAD.ActiveDocument.ActiveObject.Name)
- FreeCAD.ActiveDocument.ActiveObject.Label="PTHs"
- THPs_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #say(Holes_name)
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.67,1.00,0.50)
+ # say(FreeCAD.ActiveDocument.ActiveObject.Name)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "PTHs"
+ THPs_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ # say(Holes_name)
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.67, 1.00, 0.50)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 70
- fp_group=FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", footprint_name+'fp')
+ fp_group = FreeCAD.ActiveDocument.addObject("App::DocumentObjectGroup", footprint_name + "fp")
say(fp_group.Label)
some_element = False
- list=[]
- if len(FCrtYd)>0:
+ list = []
+ if len(FCrtYd) > 0:
obj6 = FreeCAD.ActiveDocument.getObject(FCrtYd_name)
list.append(FCrtYd_name)
fp_group.addObject(obj6)
some_element = True
- if len(FFab)>0:
+ if len(FFab) > 0:
obj7 = FreeCAD.ActiveDocument.getObject(FFab_name)
list.append(FFab_name)
fp_group.addObject(obj7)
some_element = True
- if len(FrontSilk)>0:
+ if len(FrontSilk) > 0:
obj2 = FreeCAD.ActiveDocument.getObject(FSilk_name)
list.append(FSilk_name)
fp_group.addObject(obj2)
some_element = True
- if len(BCrtYd)>0:
+ if len(BCrtYd) > 0:
obj6 = FreeCAD.ActiveDocument.getObject(BCrtYd_name)
list.append(BCrtYd_name)
fp_group.addObject(obj6)
some_element = True
- if len(BFab)>0:
+ if len(BFab) > 0:
obj7 = FreeCAD.ActiveDocument.getObject(BFab_name)
list.append(BFab_name)
fp_group.addObject(obj7)
some_element = True
- if len(BotSilk)>0:
+ if len(BotSilk) > 0:
obj2 = FreeCAD.ActiveDocument.getObject(BSilk_name)
list.append(BSilk_name)
fp_group.addObject(obj2)
some_element = True
- if len(EdgeCuts)>0:
+ if len(EdgeCuts) > 0:
obj2 = FreeCAD.ActiveDocument.getObject(ECuts_name)
list.append(ECuts_name)
fp_group.addObject(obj2)
some_element = True
- if len(TopPadList)>0:
+ if len(TopPadList) > 0:
obj3 = FreeCAD.ActiveDocument.getObject(TopPads_name)
fp_group.addObject(obj3)
list.append(TopPads_name)
some_element = True
- if len(BotPadList)>0:
+ if len(BotPadList) > 0:
obj4 = FreeCAD.ActiveDocument.getObject(BotPads_name)
fp_group.addObject(obj4)
list.append(BotPads_name)
some_element = True
- if len(TopNetTieList)>0:
+ if len(TopNetTieList) > 0:
obj_3 = FreeCAD.ActiveDocument.getObject(TopNetTie_name)
fp_group.addObject(obj_3)
list.append(TopNetTie_name)
some_element = True
- if len(BotNetTieList)>0:
+ if len(BotNetTieList) > 0:
obj_4 = FreeCAD.ActiveDocument.getObject(BotNetTie_name)
fp_group.addObject(obj_4)
list.append(BotNetTie_name)
some_element = True
- #objFp=Part.makeCompound(list)
- #Part.show(objFp)
- #say(list)
- if some_element:
- doc=FreeCAD.ActiveDocument
- fp_objs=[]
- list1=[]
+ # objFp=Part.makeCompound(list)
+ # Part.show(objFp)
+ # say(list)
+ if some_element:
+ doc = FreeCAD.ActiveDocument
+ fp_objs = []
+ list1 = []
for obj in fp_group.Group:
- #if (obj.Label==fp_group.Label):
- #FreeCADGui.Selection.addSelection(obj)
- shape=obj.Shape.copy()
- #shape_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ # if (obj.Label==fp_group.Label):
+ # FreeCADGui.Selection.addSelection(obj)
+ shape = obj.Shape.copy()
+ # shape_name=FreeCAD.ActiveDocument.ActiveObject.Name
list1.append(shape)
- #Part.show(shape)
+ # Part.show(shape)
fp_objs.append(obj)
- #say("added")
+ # say("added")
#
- #fp_objs.copy
- #objFp=Part.makeCompound(shape)
- objFp=Part.makeCompound(list1)
+ # fp_objs.copy
+ # objFp=Part.makeCompound(shape)
+ objFp = Part.makeCompound(list1)
Part.show(objFp)
-
+
obj = FreeCAD.ActiveDocument.ActiveObject
- #say("h")
- FreeCADGui.Selection.addSelection(obj) # select the object
+ # say("h")
+ FreeCADGui.Selection.addSelection(obj) # select the object
createSolidBBox2(obj)
- bbox=FreeCAD.ActiveDocument.ActiveObject
- FreeCAD.ActiveDocument.ActiveObject.Label ="Pcb_solid"
- pcb_solid_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ bbox = FreeCAD.ActiveDocument.ActiveObject
+ FreeCAD.ActiveDocument.ActiveObject.Label = "Pcb_solid"
+ pcb_solid_name = FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.removeObject(obj.Name)
-
- #FreeCADGui.ActiveDocument.getObject(bbox.Name).BoundingBox = True
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.664,0.664,0.496)
+
+ # FreeCADGui.ActiveDocument.getObject(bbox.Name).BoundingBox = True
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.664, 0.664, 0.496)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 80
- #obj6 = FreeCAD.ActiveDocument.getObject(bbox.Name)
+ # obj6 = FreeCAD.ActiveDocument.getObject(bbox.Name)
fp_group.addObject(bbox)
-
- if len(HoleList)>0:
+
+ if len(HoleList) > 0:
cut_base = FreeCAD.ActiveDocument.getObject(pcb_solid_name).Shape
for drill in HoleList:
- #Holes = Part.makeCompound(HoleList)
+ # Holes = Part.makeCompound(HoleList)
hole = Part.makeSolid(drill)
- #Part.show(hole)
- #hole_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #cutter = FreeCAD.ActiveDocument.getObject(hole_name).Shape
- cut_base=cut_base.cut(hole)
+ # Part.show(hole)
+ # hole_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ # cutter = FreeCAD.ActiveDocument.getObject(hole_name).Shape
+ cut_base = cut_base.cut(hole)
Part.show(cut_base)
- pcb_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.ActiveObject.Label ="Pcb-base"
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.664,0.664,0.496)
+ FreeCAD.ActiveDocument.ActiveObject.Label = "Pcb-base"
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.664, 0.664, 0.496)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 80
- #say("cut")
- pcb=FreeCAD.ActiveDocument.ActiveObject
+ # say("cut")
+ pcb = FreeCAD.ActiveDocument.ActiveObject
fp_group.addObject(pcb)
- #say("added")
- #FreeCAD.activeDocument().recompute()
+ # say("added")
+ # FreeCAD.activeDocument().recompute()
FreeCAD.ActiveDocument.removeObject(pcb_solid_name)
- if len(TopPadList)>0:
+ if len(TopPadList) > 0:
FreeCAD.ActiveDocument.getObject(TopPads_name).Label = "TopPads_"
cut_base = FreeCAD.ActiveDocument.getObject(TopPads_name).Shape
- holes=FreeCAD.ActiveDocument.getObject(Holes_name)
- cut_base=cut_base.cut(holes.Shape)
+ holes = FreeCAD.ActiveDocument.getObject(Holes_name)
+ cut_base = cut_base.cut(holes.Shape)
Part.show(cut_base)
- Pads_top_name=FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.ActiveObject.Label = "TopPads"
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.664,0.664,0.496)
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.664, 0.664, 0.496)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 80
- #say("cut")
- Pads_top=FreeCAD.ActiveDocument.ActiveObject
+ # say("cut")
+ Pads_top = FreeCAD.ActiveDocument.ActiveObject
fp_group.addObject(Pads_top)
- #say("added")
- #FreeCAD.activeDocument().recompute()
+ # say("added")
+ # FreeCAD.activeDocument().recompute()
FreeCAD.ActiveDocument.removeObject(TopPads_name)
- if len(BotPadList)>0:
+ if len(BotPadList) > 0:
cut_base = FreeCAD.ActiveDocument.getObject(BotPads_name).Shape
FreeCAD.ActiveDocument.getObject(BotPads_name).Label = "BotPads_"
- holes=FreeCAD.ActiveDocument.getObject(Holes_name)
- cut_base=cut_base.cut(holes.Shape)
+ holes = FreeCAD.ActiveDocument.getObject(Holes_name)
+ cut_base = cut_base.cut(holes.Shape)
Part.show(cut_base)
- Pads_bot_name=FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.ActiveObject.Label = "BotPads"
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.664,0.664,0.496)
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.664, 0.664, 0.496)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 80
- #say("cut")
- Pads_bot=FreeCAD.ActiveDocument.ActiveObject
+ # say("cut")
+ Pads_bot = FreeCAD.ActiveDocument.ActiveObject
fp_group.addObject(Pads_bot)
- #say("added")
- #FreeCAD.activeDocument().recompute()
+ # say("added")
+ # FreeCAD.activeDocument().recompute()
FreeCAD.ActiveDocument.removeObject(BotPads_name)
-
- if len(TopNetTieList)>0:
+
+ if len(TopNetTieList) > 0:
FreeCAD.ActiveDocument.getObject(TopNetTie_name).Label = "TopNetTie_"
cut_base = FreeCAD.ActiveDocument.getObject(TopNetTie_name).Shape
- holes=FreeCAD.ActiveDocument.getObject(Holes_name)
- cut_base=cut_base.cut(holes.Shape)
+ holes = FreeCAD.ActiveDocument.getObject(Holes_name)
+ cut_base = cut_base.cut(holes.Shape)
Part.show(cut_base)
- NetTie_top_name=FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.ActiveObject.Label = "TopNetTie"
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.664,0.664,0.496)
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.664, 0.664, 0.496)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 80
- #say("cut")
- NetTie_top=FreeCAD.ActiveDocument.ActiveObject
+ # say("cut")
+ NetTie_top = FreeCAD.ActiveDocument.ActiveObject
fp_group.addObject(NetTie_top)
- #say("added")
- #FreeCAD.activeDocument().recompute()
+ # say("added")
+ # FreeCAD.activeDocument().recompute()
FreeCAD.ActiveDocument.removeObject(TopNetTie_name)
- if len(BotNetTieList)>0:
+ if len(BotNetTieList) > 0:
FreeCAD.ActiveDocument.getObject(BotNetTie_name).Label = "BotNetTie_"
cut_base = FreeCAD.ActiveDocument.getObject(BotNetTie_name).Shape
- holes=FreeCAD.ActiveDocument.getObject(Holes_name)
- cut_base=cut_base.cut(holes.Shape)
+ holes = FreeCAD.ActiveDocument.getObject(Holes_name)
+ cut_base = cut_base.cut(holes.Shape)
Part.show(cut_base)
- NetTie_bot_name=FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.ActiveObject.Label = "BotNetTie"
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.664,0.664,0.496)
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.664, 0.664, 0.496)
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 80
- #say("cut")
- NetTie_bot=FreeCAD.ActiveDocument.ActiveObject
+ # say("cut")
+ NetTie_bot = FreeCAD.ActiveDocument.ActiveObject
fp_group.addObject(NetTie_bot)
- #say("added")
- #FreeCAD.activeDocument().recompute()
+ # say("added")
+ # FreeCAD.activeDocument().recompute()
FreeCAD.ActiveDocument.removeObject(BotNetTie_name)
-
+
obj5 = FreeCAD.ActiveDocument.getObject(Holes_name)
fp_group.addObject(obj5)
list.append(Holes_name)
@@ -11075,15 +11903,15 @@ def routineDrawFootPrint(content,name):
fp_group.addObject(obj6)
list.append(THPs_name)
FreeCAD.ActiveDocument.removeObject(Holes_name)
-
+
else:
- pcb=FreeCAD.ActiveDocument.ActiveObject
+ pcb = FreeCAD.ActiveDocument.ActiveObject
# copying pcb to FeaturePython to assign fixedPosition for assembly2
- Pcb_obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython","newPCB")
- Pcb_obj.Label="Pcb"
- Pcb_obj.addProperty("App::PropertyBool","fixedPosition","importPart")
+ Pcb_obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython", "newPCB")
+ Pcb_obj.Label = "Pcb"
+ Pcb_obj.addProperty("App::PropertyBool", "fixedPosition", "importPart")
Pcb_obj.Shape = pcb.Shape.copy()
- Pcb_obj.ViewObject.Proxy=0
+ Pcb_obj.ViewObject.Proxy = 0
# for p in pcb.ViewObject.PropertiesList: #assuming that the user may change the appearance of parts differently depending on the assembly.
# if hasattr(Pcb_obj.ViewObject, p) and p not in ['DiffuseColor']:
# setattr(Pcb_obj.ViewObject, p, getattr(pcb.ViewObject, p))
@@ -11097,398 +11925,419 @@ def routineDrawFootPrint(content,name):
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 79
FreeCADGui.ActiveDocument.ActiveObject.Transparency = 80
FreeCAD.ActiveDocument.removeObject(pcb.Name)
-
- list2=[]
- list2_objs=[]
+
+ list2 = []
+ list2_objs = []
for obj in fp_group.Group:
# do what you want to automate
- #if (obj.Label==fp_group.Label):
- #FreeCADGui.Selection.addSelection(obj)
- shape=obj.Shape.copy()
- #shape_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ # if (obj.Label==fp_group.Label):
+ # FreeCADGui.Selection.addSelection(obj)
+ shape = obj.Shape.copy()
+ # shape_name=FreeCAD.ActiveDocument.ActiveObject.Name
list2.append(shape)
- #Part.show(shape)
+ # Part.show(shape)
list2_objs.append(obj)
- #say("added")
- #say(list2)
- #say('here1')
-
- #Draft.rotate(list2_objs,90.0,FreeCAD.Vector(0.0,0.0,0.0),axis=FreeCAD.Vector(-0.0,-0.0,1.0),copy=False)
- #say('here1')
-
- rot=[0,0,rot_wrl]
+ # say("added")
+ # say(list2)
+ # say('here1')
+
+ # Draft.rotate(list2_objs,90.0,FreeCAD.Vector(0.0,0.0,0.0),axis=FreeCAD.Vector(-0.0,-0.0,1.0),copy=False)
+ # say('here1')
+
+ rot = [0, 0, rot_wrl]
rotateObjs(list2_objs, rot)
-
+
for obj in fp_group.Group:
FreeCADGui.Selection.removeSelection(obj)
- #say('here2')
+ # say('here2')
FreeCAD.activeDocument().recompute()
- if len(sys.argv)<4:
- #sayerr("view fitting3")
- #sayerr(sys.argv)
- if (zfit):
+ if len(sys.argv) < 4:
+ # sayerr("view fitting3")
+ # sayerr(sys.argv)
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- #pads_found=getPadsList(content)
+ # pads_found=getPadsList(content)
else:
- sayerr('internal layers not supported or fotprint empty')
+ sayerr("internal layers not supported or fotprint empty")
doc.commitTransaction()
- say('closing Transaction \'opening_kicad_footprint\'')
+ say("closing Transaction 'opening_kicad_footprint'")
+
+
###
-def routineDrawIDF(doc,filename):
+
+def routineDrawIDF(doc, filename):
"""process_emn(document, filename)-> adds emn geometry from emn file"""
global start_time
- msg='IDF_ImporterVersion='+IDF_ImporterVersion
+ msg = "IDF_ImporterVersion=" + IDF_ImporterVersion
say(msg)
- #emnfile=pythonopen(filename, "r")
- emnfile=pythonopen(filename, "rb")
- emn_unit=1.0 #presume millimeter like emn unit
- emn_version=2 #presume emn_version 2
- board_thickness=0 #presume 0 board height
- board_outline=[] #no outline
- drills=[] #no drills
- placement=[] #no placement
- place_item=[] #empty place item
- emnlines=emnfile.readlines()
- emnfile.close()
- passed_sections=[]
- current_section=""
- section_counter=0
- ignore_hole_size=min_drill_size
- #say((emnlines))
+ # emnfile=pythonopen(filename, "r")
+ emnfile = pythonopen(filename, "rb")
+ emn_unit = 1.0 # presume millimeter like emn unit
+ emn_version = 2 # presume emn_version 2
+ board_thickness = 0 # presume 0 board height
+ board_outline = [] # no outline
+ drills = [] # no drills
+ placement = [] # no placement
+ place_item = [] # empty place item
+ emnlines = emnfile.readlines()
+ emnfile.close()
+ passed_sections = []
+ current_section = ""
+ section_counter = 0
+ ignore_hole_size = min_drill_size
+ # say((emnlines))
for emnline in emnlines:
- emnrecords=split_records(emnline)
- if len( emnrecords )==0 : continue
- if len( emnrecords[0] )>4 and emnrecords[0][0:4]==".END":
+ emnrecords = split_records(emnline)
+ if len(emnrecords) == 0:
+ continue
+ if len(emnrecords[0]) > 4 and emnrecords[0][0:4] == ".END":
passed_sections.append(current_section)
- current_section=""
- elif emnrecords[0][0]==".":
- current_section=emnrecords[0]
- section_counter=0
- section_counter+=1
- if current_section==".HEADER" and section_counter==2:
- emn_version=int(float(emnrecords[1]))
- say("Emn version: "+emnrecords[1])
- if current_section==".HEADER" and section_counter==3 and emnrecords[1]=="THOU":
- emn_unit=0.0254
- say("UNIT THOU" )
- if current_section==".HEADER" and section_counter==3 and emnrecords[1]=="TNM":
- emn_unit=0.000010
- say("TNM" )
- if current_section==".BOARD_OUTLINE" and section_counter==2:
- board_thickness=emn_unit*float(emnrecords[0])
- say("Found board thickness "+emnrecords[0])
- if current_section==".BOARD_OUTLINE" and section_counter>2:
- board_outline.append([int(emnrecords[0]),float(emnrecords[1])*emn_unit,float(emnrecords[2])*emn_unit,float(emnrecords[3])])
- if current_section==".DRILLED_HOLES" and section_counter>1 and float(emnrecords[0])*emn_unit>ignore_hole_size:
- drills.append([float(emnrecords[0])*emn_unit,float(emnrecords[1])*emn_unit,float(emnrecords[2])*emn_unit])
- if current_section==".PLACEMENT" and section_counter>1 and fmod(section_counter,2)==0:
- place_item=[]
- place_item.append(emnrecords[2]) #Reference designator
- place_item.append(emnrecords[1]) #Component part number
- place_item.append(emnrecords[0]) #Package name
- if current_section==".PLACEMENT" and section_counter>1 and fmod(section_counter,2)==1:
- place_item.append(float(emnrecords[0])*emn_unit) #X
- place_item.append(float(emnrecords[1])*emn_unit) #Y
- if emn_version==3:
- place_item.append(float(emnrecords[2])*emn_unit) #Z maui
- #say("\nZ="+(str(float(emnrecords[2]))))
- place_item.append(float(emnrecords[emn_version])) #Rotation
- place_item.append(emnrecords[emn_version+1]) #Side
- place_item.append(emnrecords[emn_version+2]) #Place Status
+ current_section = ""
+ elif emnrecords[0][0] == ".":
+ current_section = emnrecords[0]
+ section_counter = 0
+ section_counter += 1
+ if current_section == ".HEADER" and section_counter == 2:
+ emn_version = int(float(emnrecords[1]))
+ say("Emn version: " + emnrecords[1])
+ if current_section == ".HEADER" and section_counter == 3 and emnrecords[1] == "THOU":
+ emn_unit = 0.0254
+ say("UNIT THOU")
+ if current_section == ".HEADER" and section_counter == 3 and emnrecords[1] == "TNM":
+ emn_unit = 0.000010
+ say("TNM")
+ if current_section == ".BOARD_OUTLINE" and section_counter == 2:
+ board_thickness = emn_unit * float(emnrecords[0])
+ say("Found board thickness " + emnrecords[0])
+ if current_section == ".BOARD_OUTLINE" and section_counter > 2:
+ board_outline.append(
+ [
+ int(emnrecords[0]),
+ float(emnrecords[1]) * emn_unit,
+ float(emnrecords[2]) * emn_unit,
+ float(emnrecords[3]),
+ ],
+ )
+ if (
+ current_section == ".DRILLED_HOLES"
+ and section_counter > 1
+ and float(emnrecords[0]) * emn_unit > ignore_hole_size
+ ):
+ drills.append(
+ [float(emnrecords[0]) * emn_unit, float(emnrecords[1]) * emn_unit, float(emnrecords[2]) * emn_unit],
+ )
+ if current_section == ".PLACEMENT" and section_counter > 1 and fmod(section_counter, 2) == 0:
+ place_item = []
+ place_item.append(emnrecords[2]) # Reference designator
+ place_item.append(emnrecords[1]) # Component part number
+ place_item.append(emnrecords[0]) # Package name
+ if current_section == ".PLACEMENT" and section_counter > 1 and fmod(section_counter, 2) == 1:
+ place_item.append(float(emnrecords[0]) * emn_unit) # X
+ place_item.append(float(emnrecords[1]) * emn_unit) # Y
+ if emn_version == 3:
+ place_item.append(float(emnrecords[2]) * emn_unit) # Z maui
+ # say("\nZ="+(str(float(emnrecords[2]))))
+ place_item.append(float(emnrecords[emn_version])) # Rotation
+ place_item.append(emnrecords[emn_version + 1]) # Side
+ place_item.append(emnrecords[emn_version + 2]) # Place Status
say(str(place_item))
placement.append(place_item)
-
+
say("\n".join(passed_sections))
- #say(board_outline)
- say("Proceed "+str(Process_board_outline(doc,board_outline,drills,board_thickness))+" outlines")
+ # say(board_outline)
+ say("Proceed " + str(Process_board_outline(doc, board_outline, drills, board_thickness)) + " outlines")
## place_steps(doc,placement,board_thickness)
-
+
+
###
-def Process_board_outline(doc,board_outline,drills,board_thickness):
+def Process_board_outline(doc, board_outline, drills, board_thickness):
"""Process_board_outline(doc,board_outline,drills,board_thickness)-> number proccesed loops
- adds emn geometry from emn file"""
+ adds emn geometry from emn file"""
global start_time, use_AppPart, force_oldGroups, use_Links, use_LinkGroups
-
- vertex_index=-1; #presume no vertex
- lines=-1 #presume no lines
- out_shape=[]
- out_face=[]
+
+ vertex_index = -1 # presume no vertex
+ lines = -1 # presume no lines
+ out_shape = []
+ out_face = []
for point in board_outline:
- vertex=Base.Vector(point[1],point[2],0)
- vertex_index+=1
- if vertex_index==0:
- lines=point[0]
- elif lines==point[0]:
- if point[3]!=0 and point[3]!=360:
- out_shape.append(Part.Arc(prev_vertex,mid_point(prev_vertex,vertex,point[3]),vertex))
- #say("mid point "+str(mid_point))
- elif point[3]==360:
- per_point=Per_point(prev_vertex,vertex)
- out_shape.append(Part.Arc(per_point,mid_point(per_point,vertex,point[3]/2),vertex))
- out_shape.append(Part.Arc(per_point,mid_point(per_point,vertex,-point[3]/2),vertex))
+ vertex = Base.Vector(point[1], point[2], 0)
+ vertex_index += 1
+ if vertex_index == 0:
+ lines = point[0]
+ elif lines == point[0]:
+ if point[3] != 0 and point[3] != 360:
+ out_shape.append(Part.Arc(prev_vertex, mid_point(prev_vertex, vertex, point[3]), vertex))
+ # say("mid point "+str(mid_point))
+ elif point[3] == 360:
+ per_point = Per_point(prev_vertex, vertex)
+ out_shape.append(Part.Arc(per_point, mid_point(per_point, vertex, point[3] / 2), vertex))
+ out_shape.append(Part.Arc(per_point, mid_point(per_point, vertex, -point[3] / 2), vertex))
else:
- out_shape.append(PLine(prev_vertex,vertex))
+ out_shape.append(PLine(prev_vertex, vertex))
else:
- out_shape=Part.Shape(out_shape)
- out_shape=Part.Wire(out_shape.Edges)
+ out_shape = Part.Shape(out_shape)
+ out_shape = Part.Wire(out_shape.Edges)
out_face.append(Part.Face(out_shape))
- out_shape=[]
- vertex_index=0
- lines=point[0]
- prev_vertex=vertex
- if lines!=-1:
- out_shape=Part.Shape(out_shape)
- out_shape=Part.Wire(out_shape.Edges)
+ out_shape = []
+ vertex_index = 0
+ lines = point[0]
+ if lines != -1:
+ out_shape = Part.Shape(out_shape)
+ out_shape = Part.Wire(out_shape.Edges)
out_face.append(Part.Face(out_shape))
- outline=out_face[0]
+ outline = out_face[0]
say("Added outline")
- if len(out_face)>1:
+ if len(out_face) > 1:
say("Cutting shape inside outline")
- for otl_cut in out_face[1: ]:
- outline=outline.cut(otl_cut)
- #say("Cutting shape inside outline")
- if len(drills)>0:
+ for otl_cut in out_face[1:]:
+ outline = outline.cut(otl_cut)
+ # say("Cutting shape inside outline")
+ if len(drills) > 0:
say("Cutting holes inside outline")
for drill in drills:
- #say("Cutting hole inside outline")
- out_shape=Part.makeCircle(drill[0]/2, Base.Vector(drill[1],drill[2],0))
- out_shape=Part.Wire(out_shape.Edges)
- outline=outline.cut(Part.Face(out_shape))
- doc_outline=doc.addObject("Part::Feature","Pcb")
- doc_outline.Shape=outline
- #FreeCADGui.Selection.addSelection(doc_outline)
- #FreeCADGui.runCommand("Draft_Upgrade")
- #outline=FreeCAD.ActiveDocument.getObject("Union").Shape
- #FreeCAD.ActiveDocument.removeObject("Union")
- #doc_outline=doc.addObject("Part::Feature","Board_outline")
- doc_outline.Shape=outline.extrude(Base.Vector(0,0,-board_thickness))
+ # say("Cutting hole inside outline")
+ out_shape = Part.makeCircle(drill[0] / 2, Base.Vector(drill[1], drill[2], 0))
+ out_shape = Part.Wire(out_shape.Edges)
+ outline = outline.cut(Part.Face(out_shape))
+ doc_outline = doc.addObject("Part::Feature", "Pcb")
+ doc_outline.Shape = outline
+ # FreeCADGui.Selection.addSelection(doc_outline)
+ # FreeCADGui.runCommand("Draft_Upgrade")
+ # outline=FreeCAD.ActiveDocument.getObject("Union").Shape
+ # FreeCAD.ActiveDocument.removeObject("Union")
+ # doc_outline=doc.addObject("Part::Feature","Board_outline")
+ doc_outline.Shape = outline.extrude(Base.Vector(0, 0, -board_thickness))
if use_AppPart and not force_oldGroups:
- #sayw("creating hierarchy")
+ # sayw("creating hierarchy")
## to evaluate to add App::Part hierarchy
- doc.Tip = doc.addObject('App::Part','Board_Geoms')
- doc.Board_Geoms.Label = 'Board_Geoms'
+ doc.Tip = doc.addObject("App::Part", "Board_Geoms")
+ doc.Board_Geoms.Label = "Board_Geoms"
try:
- doc.Board_Geoms.License = ''
- doc.Board_Geoms.LicenseURL = ''
+ doc.Board_Geoms.License = ""
+ doc.Board_Geoms.LicenseURL = ""
except:
pass
- grp=doc.Board_Geoms
- #FreeCADGui.activeView().setActiveObject('Board_Geoms', doc.Board_Geoms)
+ grp = doc.Board_Geoms
+ # FreeCADGui.activeView().setActiveObject('Board_Geoms', doc.Board_Geoms)
## end hierarchy
else:
- #sayerr("creating flat groups")
- grp=doc.addObject("App::DocumentObjectGroup", "Board_Geoms")
+ # sayerr("creating flat groups")
+ grp = doc.addObject("App::DocumentObjectGroup", "Board_Geoms")
grp.addObject(doc_outline)
- #grp.addObject(Sketch)
- doc.Pcb.ViewObject.ShapeColor = (colr,colg,colb)
+ # grp.addObject(Sketch)
+ doc.Pcb.ViewObject.ShapeColor = (colr, colg, colb)
say_time()
- #say(str(start_time));say('*'+str(end_milli_time)+'start-end')
- #FreeCADGui.activeDocument().activeView().viewAxometric()
+ # say(str(start_time));say('*'+str(end_milli_time)+'start-end')
+ # FreeCADGui.activeDocument().activeView().viewAxometric()
FreeCADGui.activeDocument().activeView().viewTop()
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- #doc.Pcb.ViewObject.ShapeColor=(0.0, 0.5, 0.0, 0.0)
- return lines+1
+ # doc.Pcb.ViewObject.ShapeColor=(0.0, 0.5, 0.0, 0.0)
+ return lines + 1
###
def split_records(line_record):
"""split_records(line_record)-> list of strings(records)
-
- standard separator list separator is space, records containing encapsulated by " """
- split_result=[]
- quote_pos=line_record.find('"')
- while quote_pos!=-1:
- if quote_pos>0:
- split_result.extend(line_record[ :quote_pos].split())
- line_record=line_record[quote_pos: ]
- quote_pos=line_record.find('"',1)
- else:
- quote_pos=line_record.find('"',1)
- if quote_pos!=-1:
- split_result.append(line_record[ :quote_pos+1])
- line_record=line_record[quote_pos+1: ]
+
+ standard separator list separator is space, records containing encapsulated by " """
+ split_result = []
+ quote_pos = line_record.find('"')
+ while quote_pos != -1:
+ if quote_pos > 0:
+ split_result.extend(line_record[:quote_pos].split())
+ line_record = line_record[quote_pos:]
+ quote_pos = line_record.find('"', 1)
+ else:
+ quote_pos = line_record.find('"', 1)
+ if quote_pos != -1:
+ split_result.append(line_record[: quote_pos + 1])
+ line_record = line_record[quote_pos + 1 :]
else:
- split_result.append(line_record)
- line_record=""
- quote_pos=line_record.find('"')
+ split_result.append(line_record)
+ line_record = ""
+ quote_pos = line_record.find('"')
split_result.extend(line_record.split())
return split_result
+
+
###
def findWires(edges):
def verts(shape):
- return [shape.Vertexes[0].Point,shape.Vertexes[-1].Point]
+ return [shape.Vertexes[0].Point, shape.Vertexes[-1].Point]
+
def group(shapes):
shapesIn = shapes[:]
pointTst = []
- pointOut =[]
- for s in shapesIn :
- pointTst=pointTst+[s.Vertexes[0].Point]
- pointTst=pointTst+[s.Vertexes[-1].Point]
- say( pointTst )
+ pointOut = []
+ for s in shapesIn:
+ pointTst = [*pointTst, s.Vertexes[0].Point]
+ pointTst = [*pointTst, s.Vertexes[-1].Point]
+ say(pointTst)
changed = False
for s in shapesIn:
if len(s.Vertexes) < 2:
- say( "one vertex, its a circle, just add" )
- else:
+ say("one vertex, its a circle, just add")
+ else:
for v in verts(s):
- twoDot=0
+ twoDot = 0
for vv in pointTst:
if v == vv:
- twoDot=twoDot+1
- if v==vv and twoDot==2 :
+ twoDot = twoDot + 1
+ if v == vv and twoDot == 2:
changed = True
- say( "found matching vert" )
+ say("found matching vert")
break
- if twoDot<2:
- say( "didn't find any matching vert..." )
+ if twoDot < 2:
+ say("didn't find any matching vert...")
pointOut.append(v)
- say( "Dots non connected"); say(pointOut)
- return(changed,pointOut)
+ say("Dots non connected")
+ say(pointOut)
+ return (changed, pointOut)
+
def joint(point):
- for p in range(len(point)/2) :
+ for p in range(len(point) / 2):
say(point)
- deltI=Part.Vertex(100,100,100).Point
- pos=1
- for pp in range(len(point)-1) :
- say( "position:") ;say( pp+1 )
- if len(point)-1>1:
- deltN=(point[0]-point[pp+1])
- if deltN.Length 1:
+ deltN = point[0] - point[pp + 1]
+ if deltN.Length < deltI.Length:
+ deltI = deltN
+ pos = pp + 1
+ say("changement")
+ say(pos)
else:
- pos=1
- say( "points a joindre");say(point[0]);say( point[pos] )
- if point[0]!=point[pos]:
- Part.show(Part.makePolygon([point[0],point[pos]]))
+ pos = 1
+ say("points a joindre")
+ say(point[0])
+ say(point[pos])
+ if point[0] != point[pos]:
+ Part.show(Part.makePolygon([point[0], point[pos]]))
else:
- say( "WARNING les points ont la meme valeurs " )
+ say("WARNING les points ont la meme valeurs ")
point.pop(0)
- point.pop(pos-1)
- point=0 #to have a return normally void
- return(point)
- working = True
+ point.pop(pos - 1)
+ return 0 # to have a return normally void
+
edgeSet = edges
result = group(edgeSet)
- working = result[0]
+ result[0]
edgeSet = result[1]
joint(result[1])
- return result[1]
-#
+ return result[1]
+
def distance(p0, p1):
- return sqrt((p0[0] - p1[0])**2 + (p0[1] - p1[1])**2)
-#
-class OSCD2Dg_Overlappingfaces():
- '''combines overlapping faces together'''
- def __init__(self,facelist):
- self.sortedfaces = sorted(facelist,key=(lambda shape: shape.Area),reverse=True)
+ return sqrt((p0[0] - p1[0]) ** 2 + (p0[1] - p1[1]) ** 2)
+
+
+class OSCD2Dg_Overlappingfaces:
+ """combines overlapping faces together"""
+
+ def __init__(self, facelist):
+ self.sortedfaces = sorted(facelist, key=(lambda shape: shape.Area), reverse=True)
self.builddepdict()
- #self.faceindex = {}
- #for idx,face in enumerate(self.sortesfaces):
+ # self.faceindex = {}
+ # for idx,face in enumerate(self.sortesfaces):
# self.faceindex[face.hashCode()] = idx
-# def __len__(self):
-# return len(self.sortedfaces)
+ # def __len__(self):
+ # return len(self.sortedfaces)
@staticmethod
- def dofacesoverlapboundbox(bigface,smallface):
+ def dofacesoverlapboundbox(bigface, smallface):
return bigface.BoundBox.isIntersection(smallface.BoundBox)
@staticmethod
- def dofacesoverlapallverts(bigface,smallface):
- def vertsinface(f1,verts,tol=0.001,inface=True):
- '''check if all given verts are inside shape f1'''
- return all([f1.isInside(vert.Point,tol,inface) for vert in verts])
- return vertsinface(bigface,smallface.Vertexes)
+ def dofacesoverlapallverts(bigface, smallface):
+ def vertsinface(f1, verts, tol=0.001, inface=True):
+ """check if all given verts are inside shape f1"""
+ return all(f1.isInside(vert.Point, tol, inface) for vert in verts)
+
+ return vertsinface(bigface, smallface.Vertexes)
@staticmethod
- def dofacesoverlapproximity(bigface,smallface):
- l1,l2 = bigface.proximity(smallface)
+ def dofacesoverlapproximity(bigface, smallface):
+ l1, l2 = bigface.proximity(smallface)
return len(l1) > 0 or len(l2) > 0
@staticmethod
- def dofacesoverlapboolean(bigface,smallface):
- #import FreeCAD,FreeCADGui
- #FreeCAD.Console.PrintLog('intersecting %d %d\n'%(bigfacei,smallfacei))
- #FreeCADGui.updateGui()
+ def dofacesoverlapboolean(bigface, smallface):
+ # import FreeCAD,FreeCADGui
+ # FreeCAD.Console.PrintLog('intersecting %d %d\n'%(bigfacei,smallfacei))
+ # FreeCADGui.updateGui()
return bigface.common(smallface).Area > 0
def builddepdict(self):
- import Part
import itertools
- #isinsidelist = []
+
+ import Part
+
+ # isinsidelist = []
self.isinsidedict = {}
- #for bigface, smallface in itertools.combinations(sortedfaces,2):
- for bigfacei, smallfacei in\
- itertools.combinations(range(len(self.sortedfaces)),2):
+ # for bigface, smallface in itertools.combinations(sortedfaces,2):
+ for bigfacei, smallfacei in itertools.combinations(range(len(self.sortedfaces)), 2):
try:
- overlap = OSCD2Dg_Overlappingfaces.dofacesoverlapproximity(\
- self.sortedfaces[bigfacei],self.sortedfaces[smallfacei])
- except (NotImplementedError, Part.OCCError) as e:
+ overlap = OSCD2Dg_Overlappingfaces.dofacesoverlapproximity(
+ self.sortedfaces[bigfacei],
+ self.sortedfaces[smallfacei],
+ )
+ except (NotImplementedError, Part.OCCError):
try:
- overlap = OSCD2Dg_Overlappingfaces.dofacesoverlapboolean(\
- self.sortedfaces[bigfacei],\
- self.sortedfaces[smallfacei])
+ overlap = OSCD2Dg_Overlappingfaces.dofacesoverlapboolean(
+ self.sortedfaces[bigfacei],
+ self.sortedfaces[smallfacei],
+ )
except Part.OCCError:
- overlap = OSCD2Dg_Overlappingfaces.dofacesoverlapallverts(\
- self.sortedfaces[bigfacei],\
- self.sortedfaces[smallfacei])
+ overlap = OSCD2Dg_Overlappingfaces.dofacesoverlapallverts(
+ self.sortedfaces[bigfacei],
+ self.sortedfaces[smallfacei],
+ )
if overlap:
- #isinsidelist.append((bigfacei,smallfacei))
- smallinbig = self.isinsidedict.get(bigfacei,[])
+ # isinsidelist.append((bigfacei,smallfacei))
+ smallinbig = self.isinsidedict.get(bigfacei, [])
smallinbig.append(smallfacei)
if len(smallinbig) == 1:
self.isinsidedict[bigfacei] = smallinbig
@staticmethod
- def finddepth(dict1,faceidx,curdepth=0):
+ def finddepth(dict1, faceidx, curdepth=0):
if faceidx not in dict1:
- return curdepth+1
- else:
- #print dict1[faceidx],[(finddepth(dict1,childface,curdepth)) for childface in dict1[faceidx]]
- return max([(OSCD2Dg_Overlappingfaces.finddepth(dict1,childface,curdepth+1)) for childface in dict1[faceidx]])
+ return curdepth + 1
+ # print dict1[faceidx],[(finddepth(dict1,childface,curdepth)) for childface in dict1[faceidx]]
+ return max(
+ [(OSCD2Dg_Overlappingfaces.finddepth(dict1, childface, curdepth + 1)) for childface in dict1[faceidx]],
+ )
def findrootdepth(self):
- return max([OSCD2Dg_Overlappingfaces.finddepth(self.isinsidedict,fi) for fi in range(len(self.sortedfaces))])
+ return max([OSCD2Dg_Overlappingfaces.finddepth(self.isinsidedict, fi) for fi in range(len(self.sortedfaces))])
- def hasnoparent(self,faceindex):
- return OSCD2Dg_Overlappingfaces.hasnoparentstatic(self.isinsidedict,faceindex)
+ def hasnoparent(self, faceindex):
+ return OSCD2Dg_Overlappingfaces.hasnoparentstatic(self.isinsidedict, faceindex)
@staticmethod
- def hasnoparentstatic(isinsidedict,faceindex):
- if (sys.version_info > (3, 0)): #py3
- for smalllist in isinsidedict.values():
- if faceindex in smalllist:
- return False
- else: #py2
- for smalllist in isinsidedict.itervalues():
- if faceindex in smalllist:
- return False
- return True
+ def hasnoparentstatic(isinsidedict, faceindex):
+ return all(faceindex not in smalllist for smalllist in isinsidedict.values())
- #@staticmethod
- #def subtreedict(rootface,parantdict):
+ # @staticmethod
+ # def subtreedict(rootface,parantdict):
# '''biuld a subtree dictinary'''
# newdict = parantdict.copy()
# del newdict[rootface]
# return newdict
@staticmethod
- def directchildren(isinsidedict,parent):
- #return [child for child in isinsidedict.get(parent,[]) if child not in isinsidedict]
- dchildren=[]
- for child in isinsidedict.get(parent,[]):
+ def directchildren(isinsidedict, parent):
+ # return [child for child in isinsidedict.get(parent,[]) if child not in isinsidedict]
+ dchildren = []
+ for child in isinsidedict.get(parent, []):
direct = True
- import sys
- if sys.version_info[0] == 2: #if py2:
- #print('py2')
- py2=True
- else:
- py2=False
+ py2 = False
if py2:
for key, value in isinsidedict.iteritems():
if key != parent and child in value and parent not in value:
@@ -11496,245 +12345,221 @@ def directchildren(isinsidedict,parent):
else:
for key, value in isinsidedict.items():
if key != parent and child in value and parent not in value:
- direct = False
+ direct = False
if direct:
dchildren.append(child)
return dchildren
- #@staticmethod
- #def indirectchildren(isinsidedict,parent):
- # return [child for child in isinsidedict.get(parent,[]) if child in isinsidedict]
+ # @staticmethod
+ # def indirectchildren(isinsidedict,parent):
+ # return [child for child in isinsidedict.get(parent,[]) if child in isinsidedict]
@staticmethod
- def printtree(isinsidedict,facenum):
- def printtreechild(isinsidedict,facenum,parent):
- children=OSCD2Dg_Overlappingfaces.directchildren(isinsidedict,parent)
- #say 'parent %d directchild %s' % (parent,children)
+ def printtree(isinsidedict, facenum):
+ def printtreechild(isinsidedict, facenum, parent):
+ children = OSCD2Dg_Overlappingfaces.directchildren(isinsidedict, parent)
+ # say 'parent %d directchild %s' % (parent,children)
if children:
- subdict=isinsidedict.copy()
+ subdict = isinsidedict.copy()
del subdict[parent]
for child in children:
- printtreechild(subdict,facenum,child)
+ printtreechild(subdict, facenum, child)
- rootitems=[fi for fi in range(facenum) if OSCD2Dg_Overlappingfaces.hasnoparentstatic(isinsidedict,fi)]
+ rootitems = [fi for fi in range(facenum) if OSCD2Dg_Overlappingfaces.hasnoparentstatic(isinsidedict, fi)]
for rootitem in rootitems:
- printtreechild(isinsidedict,facenum,rootitem)
+ printtreechild(isinsidedict, facenum, rootitem)
- def makefeatures(self,doc):
- import FreeCAD
+ def makefeatures(self, doc):
def addshape(faceindex):
- obj=doc.addObject('Part::Feature','facefromedges_%d' % faceindex)
+ obj = doc.addObject("Part::Feature", f"facefromedges_{faceindex}")
obj.Shape = self.sortedfaces[faceindex]
obj.ViewObject.hide()
return obj
- def addfeature(faceindex,isinsidedict):
- directchildren = OSCD2Dg_Overlappingfaces.directchildren(isinsidedict,faceindex)
+ def addfeature(faceindex, isinsidedict):
+ directchildren = OSCD2Dg_Overlappingfaces.directchildren(isinsidedict, faceindex)
if len(directchildren) == 0:
- obj=addshape(faceindex)
+ obj = addshape(faceindex)
else:
- subdict=isinsidedict.copy()
+ subdict = isinsidedict.copy()
del subdict[faceindex]
- obj=doc.addObject("Part::Cut","facesfromedges_%d" % faceindex)
- obj.Base= addshape(faceindex) #we only do subtraction
+ obj = doc.addObject("Part::Cut", f"facesfromedges_{faceindex}")
+ obj.Base = addshape(faceindex) # we only do subtraction
if len(directchildren) == 1:
- obj.Tool = addfeature(directchildren[0],subdict)
+ obj.Tool = addfeature(directchildren[0], subdict)
else:
- obj.Tool = doc.addObject("Part::MultiFuse",\
- "facesfromedges_union")
- obj.Tool.Shapes = [addfeature(child,subdict)\
- for child in directchildren]
- obj.Tool.ViewObject.hide()
+ obj.Tool = doc.addObject("Part::MultiFuse", "facesfromedges_union")
+ obj.Tool.Shapes = [addfeature(child, subdict) for child in directchildren]
+ obj.Tool.ViewObject.hide()
obj.ViewObject.hide()
return obj
rootitems = [fi for fi in range(len(self.sortedfaces)) if self.hasnoparent(fi)]
for rootitem in rootitems:
- addfeature(rootitem,self.isinsidedict).ViewObject.show()
-
+ addfeature(rootitem, self.isinsidedict).ViewObject.show()
def makeshape(self):
def removefaces(rfaces):
for tfi in directchildren[::-1]:
finishedwith.append(tfi)
- #del faces[tfi]
+ # del faces[tfi]
if tfi in isinsidedict:
del isinsidedict[tfi]
- if (sys.version_info > (3, 0)): #py3
- for key,value in isinsidedict.items():
- if tfi in value:
- newlist=value[:] #we work on a shallow copy of isinsidedict
- newlist.remove(tfi)
- isinsidedict[key]=newlist
- else: #py2
- for key,value in isinsidedict.iteritems():
- if tfi in value:
- newlist=value[:] #we work on a shallow copy of isinsidedict
- newlist.remove(tfi)
- isinsidedict[key]=newlist
-
- def hasnoparent(faceindex):
- if (sys.version_info > (3, 0)): #py3
- for smalllist in self.isinsidedict.values():
- if faceindex in smalllist:
- return False
- else: #py2
- for smalllist in self.isinsidedict.itervalues():
- if faceindex in smalllist:
- return False
- return True
+ for key, value in isinsidedict.items():
+ if tfi in value:
+ newlist = value[:] # we work on a shallow copy of isinsidedict
+ newlist.remove(tfi)
+ isinsidedict[key] = newlist
- faces=self.sortedfaces[:]
- isinsidedict=self.isinsidedict.copy()
- finishedwith=[]
- while not all([OSCD2Dg_Overlappingfaces.hasnoparentstatic(isinsidedict,fi) for fi in range(len(faces))]):
- #print [(Overlappingfaces.hasnoparentstatic(isinsidedict,fi),\
- #Overlappingfaces.directchildren(isinsidedict,fi)) for fi in range(len(faces))]
+ def hasnoparent(faceindex):
+ return all(faceindex not in smalllist for smalllist in self.isinsidedict.values())
+
+ faces = self.sortedfaces[:]
+ isinsidedict = self.isinsidedict.copy()
+ finishedwith = []
+ while not all(OSCD2Dg_Overlappingfaces.hasnoparentstatic(isinsidedict, fi) for fi in range(len(faces))):
+ # print [(Overlappingfaces.hasnoparentstatic(isinsidedict,fi),\
+ # Overlappingfaces.directchildren(isinsidedict,fi)) for fi in range(len(faces))]
for fi in range(len(faces))[::-1]:
- directchildren = OSCD2Dg_Overlappingfaces.directchildren(isinsidedict,fi)
+ directchildren = OSCD2Dg_Overlappingfaces.directchildren(isinsidedict, fi)
if not directchildren:
continue
- elif len(directchildren) == 1:
- faces[fi]=faces[fi].cut(faces[directchildren[0]])
- #print fi,'-' ,directchildren[0], faces[fi],faces[directchildren[0]]
+ if len(directchildren) == 1:
+ faces[fi] = faces[fi].cut(faces[directchildren[0]])
+ # print fi,'-' ,directchildren[0], faces[fi],faces[directchildren[0]]
removefaces(directchildren)
else:
- toolface=OSCD2Dg_fusefaces([faces[tfi] for tfi in directchildren])
- faces[fi]=faces[fi].cut(toolface)
- #print fi, '- ()', directchildren, [faces[tfi] for tfi in directchildren]
+ toolface = OSCD2Dg_fusefaces([faces[tfi] for tfi in directchildren])
+ faces[fi] = faces[fi].cut(toolface)
+ # print fi, '- ()', directchildren, [faces[tfi] for tfi in directchildren]
removefaces(directchildren)
- #print fi,directchildren
- faces =[face for index,face in enumerate(faces) if index not in finishedwith]
-# return faces
+ # print fi,directchildren
+ faces = [face for index, face in enumerate(faces) if index not in finishedwith]
+ # return faces
return OSCD2Dg_fusefaces(faces)
-#
-def OSCD2Dg_superWireReverse(debuglist,closed=False):
- '''superWireReverse(debuglist,[closed]): forces a wire between edges
+
+
+def OSCD2Dg_superWireReverse(debuglist, closed=False):
+ """superWireReverse(debuglist,[closed]): forces a wire between edges
that don't necessarily have coincident endpoints. If closed=True, wire
will always be closed. debuglist has a tuple for every edge.The first
entry is the edge, the second is the flag 'does not need to be inverted'
- '''
- #taken from draftlibs
- sayerr('edges not closed... trying to solve it')
- def median(v1,v2):
+ """
+ # taken from draftlibs
+ sayerr("edges not closed... trying to solve it")
+
+ def median(v1, v2):
vd = v2.sub(v1)
- vd.scale(.5,.5,.5)
+ vd.scale(0.5, 0.5, 0.5)
return v1.add(vd)
+
try:
from DraftGeomUtils import findMidpoint
- except ImportError: #workaround for Version 0.12
- from draftlibs.fcgeo import findMidpoint #workaround for Version 0.12
+ except ImportError: # workaround for Version 0.12
+ from draftlibs.fcgeo import findMidpoint # workaround for Version 0.12
import Part
- #edges = sortEdges(edgeslist)
+
+ # edges = sortEdges(edgeslist)
# print "here 7"
# print debuglist
newedges = []
- edge_added=False
+ edge_added = False
for i in range(len(debuglist)):
curr = debuglist[i]
- if i == 0:
- if closed:
- prev = debuglist[-1]
- else:
- prev = None
- else:
- prev = debuglist[i-1]
- #print "prev=",prev
- if i == (len(debuglist)-1):
- if closed:
- nexte = debuglist[0]
- else:
- nexte = None
- else:
- nexte = debuglist[i+1]
+ prev = (debuglist[-1] if closed else None) if i == 0 else debuglist[i - 1]
+ # print "prev=",prev
+ nexte = (debuglist[0] if closed else None) if i == len(debuglist) - 1 else debuglist[i + 1]
# print i,prev,curr,nexte
# print "here loop"
if prev:
- if curr[0].Vertexes[-1*(not curr[1])].Point == \
- prev[0].Vertexes[-1*prev[1]].Point:
- p1 = curr[0].Vertexes[-1*(not curr[1])].Point
+ if curr[0].Vertexes[-1 * (not curr[1])].Point == prev[0].Vertexes[-1 * prev[1]].Point:
+ p1 = curr[0].Vertexes[-1 * (not curr[1])].Point
else:
- p1 = median(curr[0].Vertexes[-1*(not curr[1])].Point,\
- prev[0].Vertexes[-1*prev[1]].Point)
+ p1 = median(curr[0].Vertexes[-1 * (not curr[1])].Point, prev[0].Vertexes[-1 * prev[1]].Point)
else:
- p1 = curr[0].Vertexes[-1*(not curr[1])].Point
+ p1 = curr[0].Vertexes[-1 * (not curr[1])].Point
if nexte:
- if curr[0].Vertexes[-1*curr[1]].Point == \
- nexte[0].Vertexes[-1*(not nexte[1])].Point:
- p2 = nexte[0].Vertexes[-1*(not nexte[1])].Point
+ if curr[0].Vertexes[-1 * curr[1]].Point == nexte[0].Vertexes[-1 * (not nexte[1])].Point:
+ p2 = nexte[0].Vertexes[-1 * (not nexte[1])].Point
else:
- p2 = median(curr[0].Vertexes[-1*(curr[1])].Point,\
- nexte[0].Vertexes[-1*(not nexte[1])].Point)
+ p2 = median(curr[0].Vertexes[-1 * (curr[1])].Point, nexte[0].Vertexes[-1 * (not nexte[1])].Point)
else:
- p2 = curr[0].Vertexes[-1*(curr[1])].Point
+ p2 = curr[0].Vertexes[-1 * (curr[1])].Point
# print "here 8"
# print "curr[0].Curve ",curr[0].Curve
- if hasattr(Part,"LineSegment"):
- if isinstance(curr[0].Curve,Part.Line) or isinstance(curr[0].Curve,Part.LineSegment):
- #print "line",p1,p2
- newedges.append(Part.LineSegment(p1,p2).toShape())
- edge_added=True
- elif hasattr(Part,"Line"):
- if isinstance(curr[0].Curve,Part.Line):
- #print "line",p1,p2
- newedges.append(Part.Line(p1,p2).toShape())
- edge_added=True
- if isinstance(curr[0].Curve,Part.Circle):
+ if hasattr(Part, "LineSegment"):
+ if isinstance(curr[0].Curve, (Part.Line, Part.LineSegment)):
+ # print "line",p1,p2
+ newedges.append(Part.LineSegment(p1, p2).toShape())
+ edge_added = True
+ elif hasattr(Part, "Line") and isinstance(curr[0].Curve, Part.Line):
+ # print "line",p1,p2
+ newedges.append(Part.Line(p1, p2).toShape())
+ edge_added = True
+ if isinstance(curr[0].Curve, Part.Circle):
p3 = findMidpoint(curr[0])
- #print "arc",p1,p3,p2
- newedges.append(Part.Arc(p1,p3,p2).toShape())
- edge_added=True
- #else:
+ # print "arc",p1,p3,p2
+ newedges.append(Part.Arc(p1, p3, p2).toShape())
+ edge_added = True
+ # else:
if not edge_added:
- say( "Cannot superWire edges that are not lines or arcs" )
+ say("Cannot superWire edges that are not lines or arcs")
return None
# print newedges
return Part.Wire(newedges)
-#
+
+
def OSCD2Dg_endpointdistance(edges):
- '''return the distance of of vertices in path (list of edges) as
+ """return the distance of of vertices in path (list of edges) as
maximum, minimum and distance between start and endpoint
- it expects the edges to be traversed forward from starting from Vertex 0'''
- numedges=len(edges)
+ it expects the edges to be traversed forward from starting from Vertex 0"""
+ numedges = len(edges)
if numedges == 1 and len(edges[0].Vertexes) == 1:
- return 0.0,0.0,0.0
- outerdistance = edges[0].Vertexes[0].Point.sub(\
- edges[-1].Vertexes[-1].Point).Length
+ return 0.0, 0.0, 0.0
+ outerdistance = edges[0].Vertexes[0].Point.sub(edges[-1].Vertexes[-1].Point).Length
if numedges > 1:
- innerdistances=[edges[i].Vertexes[-1].Point.sub(edges[i+1].\
- Vertexes[0].Point).Length for i in range(numedges-1)]
- return max(innerdistances),min(innerdistances),outerdistance
- else:
- return 0.0,0.0,outerdistance
+ innerdistances = [
+ edges[i].Vertexes[-1].Point.sub(edges[i + 1].Vertexes[0].Point).Length for i in range(numedges - 1)
+ ]
+ return max(innerdistances), min(innerdistances), outerdistance
+ return 0.0, 0.0, outerdistance
+
def OSCD2Dg_endpointdistancedebuglist(debuglist):
- '''return the distance of of vertices in path (list of edges) as
+ """return the distance of of vertices in path (list of edges) as
maximum, minimum and distance between start and endpoint
- it it expects a 'not reversed' flag for every edge'''
- numedges=len(debuglist)
+ it it expects a 'not reversed' flag for every edge"""
+ numedges = len(debuglist)
if numedges == 1 and len(debuglist[0][0].Vertexes) == 1:
- return 0.0,0.0,0.0
- outerdistance = debuglist[0][0].Vertexes[(not debuglist[0][1])*-1].\
- Point.sub(debuglist[-1][0].Vertexes[(debuglist[-1][1])*-1].\
- Point).Length
+ return 0.0, 0.0, 0.0
+ outerdistance = (
+ debuglist[0][0]
+ .Vertexes[(not debuglist[0][1]) * -1]
+ .Point.sub(debuglist[-1][0].Vertexes[(debuglist[-1][1]) * -1].Point)
+ .Length
+ )
if numedges > 1:
- innerdistances=[debuglist[i][0].Vertexes[debuglist[i][1]*-1].\
- Point.sub(debuglist[i+1][0].Vertexes[(not debuglist[i+1][1])*\
- -1].Point).Length for i in range(numedges-1)]
- return max(innerdistances),min(innerdistances),outerdistance
- else:
- return 0.0,0.0,outerdistance
-#
-def OSCD2Dg_findConnectedEdges(edgelist,eps=1e-6,debug=False):
- '''returns a list of list of connected edges'''
+ innerdistances = [
+ debuglist[i][0]
+ .Vertexes[debuglist[i][1] * -1]
+ .Point.sub(debuglist[i + 1][0].Vertexes[(not debuglist[i + 1][1]) * -1].Point)
+ .Length
+ for i in range(numedges - 1)
+ ]
+ return max(innerdistances), min(innerdistances), outerdistance
+ return 0.0, 0.0, outerdistance
+
+
+def OSCD2Dg_findConnectedEdges(edgelist, eps=1e-6, debug=False):
+ """returns a list of list of connected edges"""
- def vertequals(v1,v2,eps=1e-6):
- '''check two vertices for equality'''
- #return all([abs(c1-c2) 0.000001: #OCC wont like it if maxd > 0.02:
+ wirelist = []
+ # for path in findConnectedEdges(edgelist,eps=eps):
+ for path, debug in zip(*OSCD2Dg_findConnectedEdges(edgelist, eps=eps, debug=True)):
+ maxd, _mind, outerd = OSCD2Dg_endpointdistancedebuglist(debug)
+ assert maxd <= eps * 2 # Assume the input to be broken
+ if maxd < eps * 2 and maxd > 0.000001: # OCC wont like it if maxd > 0.02:
# print 'endpointdistance max:%f min:%f, ends:%f' %(maxd,mind,outerd)
# print "here 5"
if True:
- tobeclosed = outerd < eps*2
+ tobeclosed = outerd < eps * 2
# OpenSCAD uses 0.001 for corase grid
- #from draftlibs import fcvec, fcgeo
- #w2=fcgeo.superWire(path,tobeclosed)
- #print "here 6a"
- w2=OSCD2Dg_superWireReverse(debug,tobeclosed)
+ # from draftlibs import fcvec, fcgeo
+ # w2=fcgeo.superWire(path,tobeclosed)
+ # print "here 6a"
+ w2 = OSCD2Dg_superWireReverse(debug, tobeclosed)
if w2 is not None:
wirelist.append(w2)
- else:#this locks up FreeCAD
- #print "here 6b"
- comp=Part.Compound(path)
- wirelist.append(comp.connectEdgesToWires(False,eps).Wires[0])
- #wirelist.append(comp.connectEdgesToWires(False,0.1).Wires[0])
+ else: # this locks up FreeCAD
+ # print "here 6b"
+ comp = Part.Compound(path)
+ wirelist.append(comp.connectEdgesToWires(False, eps).Wires[0])
+ # wirelist.append(comp.connectEdgesToWires(False,0.1).Wires[0])
else:
done = False
try:
- wire=Part.Wire(path)
- #if not close or wire.isClosed or outerd > 0.0001:
+ Part.Wire(path)
+ # if not close or wire.isClosed or outerd > 0.0001:
wirelist.append(Part.Wire(path))
done = True
except Part.OCCError:
pass
if not done:
- comp=Part.Compound(path)
- wirelist.append(comp.connectEdgesToWires(False,eps).Wires[0])
+ comp = Part.Compound(path)
+ wirelist.append(comp.connectEdgesToWires(False, eps).Wires[0])
return wirelist
-#
-def OSCD2Dg_edgestofaces(edges,algo=3,eps=0.001):
- #edges=[]
- #for shapeobj in (objs):
+
+
+def OSCD2Dg_edgestofaces(edges, algo=3, eps=0.001):
+ # edges=[]
+ # for shapeobj in (objs):
# edges.extend(shapeobj.Shape.Edges)
- #taken from Drafttools
- #from draftlibs import fcvec, fcgeo
+ # taken from Drafttools
+ # from draftlibs import fcvec, fcgeo
import Part
- #wires = fcgeo.findWires(edges)
- #print "edges: "
+
+ # wires = fcgeo.findWires(edges)
+ # print "edges: "
# for e in edges:
# print "e.Vertexes: ", e.Vertexes
# for p in e.Vertexes:
# print "points", p.Point
# print "here 4"
- wires = OSCD2Dg_edgestowires(edges,eps)
- facel=[]
+ wires = OSCD2Dg_edgestowires(edges, eps)
+ facel = []
for w in wires:
- #assert(len(w.Edges)>1)
+ # assert(len(w.Edges)>1)
if not w.isClosed():
p0 = w.Vertexes[0].Point
p1 = w.Vertexes[-1].Point
# print "p0",p0," ";print "p1",p1
edges2 = w.Edges[:]
try:
- if hasattr(Part,"LineSegment"):
- edges2.append(Part.LineSegment(p1,p0).toShape())
+ if hasattr(Part, "LineSegment"):
+ edges2.append(Part.LineSegment(p1, p0).toShape())
else:
- edges2.append(Part.Line(p1,p0).toShape())
- #edges2.append(Part.LineSegment(p1,p0).toShape())
+ edges2.append(Part.Line(p1, p0).toShape())
+ # edges2.append(Part.LineSegment(p1,p0).toShape())
w = Part.Wire(edges2)
- #w = Part.Wire(fcgeo.sortEdges(edges2))
+ # w = Part.Wire(fcgeo.sortEdges(edges2))
except Part.OCCError:
- comp=Part.Compound(edges2)
- w = comp.connectEdgesToWires(False,eps).Wires[0]
+ comp = Part.Compound(edges2)
+ w = comp.connectEdgesToWires(False, eps).Wires[0]
facel.append(Part.Face(w))
- #if w.isValid: #debugging
+ # if w.isValid: #debugging
# facel.append(Part.Face(w))
- #else:
+ # else:
# Part.show(w)
if algo is None:
return facel
- elif algo == 1: #stabale behavior
+ if algo == 1: # stabale behavior
return subtractfaces(facel)
- elif algo == 0: #return all faces
+ if algo == 0: # return all faces
return Part.Compound(facel)
- elif algo == 2:
+ if algo == 2:
return subtractfaces2(facel)
- elif algo == 3:
+ if algo == 3:
return OSCD2Dg_Overlappingfaces(facel).makeshape()
-#
+ return None
+
###
def get_mod_Ref(m):
- #if hasattr(m,'property'):
- if hasattr(m,'property'):
- for p in m.property: #kv8 fp field
- #print(str(p[0]),str(p[1]))
- if 'reference' in str(p[0]).lower():
- # if 'reference' in str(p[1]).lower():
- Ref = str(p[1])
- #print (Ref)
- #stop
- return Ref
- if hasattr(m,'fp_text'):
- for p in m.fp_text: #kv7 fp field
- #print(str(p[0]),str(p[1]))
- if 'reference' in str(p[0]).lower():
- # if 'reference' in str(p[1]).lower():
- Ref = str(p[1])
- return Ref
+ # if hasattr(m,'property'):
+ if hasattr(m, "property"):
+ for p in m.property: # kv8 fp field
+ # print(str(p[0]),str(p[1]))
+ if "reference" in str(p[0]).lower():
+ # if 'reference' in str(p[1]).lower():
+ return str(p[1])
+ # print (Ref)
+ # stop
+ if hasattr(m, "fp_text"):
+ for p in m.fp_text: # kv7 fp field
+ # print(str(p[0]),str(p[1]))
+ if "reference" in str(p[0]).lower():
+ # if 'reference' in str(p[1]).lower():
+ return str(p[1])
+ return None
+
+
###
-def DrawPCB(mypcb,lyr=None,rmv_container=None,keep_sketch=None):
+def DrawPCB(mypcb, lyr=None, rmv_container=None, keep_sketch=None):
global start_time, use_AppPart, force_oldGroups, min_drill_size
global addVirtual, load_sketch, off_x, off_y, aux_orig, grid_orig
global running_time, conv_offs, use_Links, apply_edge_tolerance, simplifyComSolid
global zfit, use_LinkGroups, fname_sfx, missingHeight
- global extrude_holes, ply_lines, bklist_dnp,blacklisted_model_elements
-
+ global extrude_holes, ply_lines, bklist_dnp, blacklisted_model_elements
+
def simu_distance(p0, p1):
- return max (abs(p0[0] - p1[0]), abs(p0[1] - p1[1]))
-
- import PySide
- import FreeCAD, Part
- from PySide import QtGui, QtCore
+ return max(abs(p0[0] - p1[0]), abs(p0[1] - p1[1]))
+
from math import pi
-
+
+ import FreeCAD
+ import Part
+ from PySide import QtCore, QtGui
+
say("PCB Loader ")
## NB use always float() to guarantee number not string!!!
- max_edges_admitted = 1500 # after this number, no sketcher would be created
-
+ max_edges_admitted = 1500 # after this number, no sketcher would be created
+
if lyr is None:
- lyr = 'Edge.Cuts'
- #load_sketch=True
+ lyr = "Edge.Cuts"
+ # load_sketch=True
get_time()
- t0=(running_time)
- #say(start_time)
-
- doc=FreeCAD.activeDocument()
+ t0 = running_time
+ # say(start_time)
+
+ doc = FreeCAD.activeDocument()
for obj in FreeCAD.ActiveDocument.Objects:
FreeCADGui.Selection.removeSelection(obj)
EdgeCuts = []
- EdgeCuts_face = []
- EdgeCuts_shape = []
PCB = []
PCB_Models = []
PCB_Geo = []
FpEdges_Geo = []
- edges=[]
+ edges = []
PCBs = []
- #print (mypcb.general) #maui errorchecking
- if hasattr(mypcb, 'general'):
- totalHeight=float(mypcb.general.thickness)
- else:
- totalHeight=1.6
+ # print (mypcb.general) #maui errorchecking
+ totalHeight = float(mypcb.general.thickness) if hasattr(mypcb, "general") else 1.6
missingHeight = False
if totalHeight == 0:
totalHeight = 1.6
missingHeight = True
- sayerr('pcb thickness = 0mm! CHANGED to 1.6mm Please fix your pcb design!')
- say('pcb thickness '+str(totalHeight)+'mm')
- version=mypcb.version
- say('kicad_pcb version ' +str(version))
+ sayerr("pcb thickness = 0mm! CHANGED to 1.6mm Please fix your pcb design!")
+ say("pcb thickness " + str(totalHeight) + "mm")
+ version = mypcb.version
+ say("kicad_pcb version " + str(version))
if version < 3:
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Error ...","... KICAD pcb version "+ str(version)+" not supported \r\n"+"\r\nplease open and save your board with the latest kicad version")
+ QtGui.QMessageBox.information(
+ None,
+ "Error ...",
+ "... KICAD pcb version "
+ + str(version)
+ + " not supported \r\n"
+ + "\r\nplease open and save your board with the latest kicad version",
+ )
sys.exit("pcb version not supported")
- elif version==3:
- Edge_Cuts_lvl=28
- Top_lvl=15
- elif version>=4:
- Edge_Cuts_lvl=44
- Top_lvl=0
- conv_offs=1.0
+ elif version == 3:
+ Edge_Cuts_lvl = 28
+ Top_lvl = 15
+ elif version >= 4:
+ Edge_Cuts_lvl = 44
+ Top_lvl = 0
+ conv_offs = 1.0
if version >= 20171114:
- conv_offs=25.4
- #getting pcb version for the internal use of 'virtual' modules
+ conv_offs = 25.4
+ # getting pcb version for the internal use of 'virtual' modules
pcbv = 4
if version == 20171130:
pcbv = 5
@@ -11984,564 +12818,698 @@ def simu_distance(p0, p1):
pcbv = 6
elif version >= 20220000:
pcbv = 6.99
- #load_sketch=False
+ # load_sketch=False
# sayerr(len(mypcb.gr_line))
# say(len(mypcb.gr_arc))
- #edg_segms = len(mypcb.gr_line)+len(mypcb.gr_arc)
+ # edg_segms = len(mypcb.gr_line)+len(mypcb.gr_arc)
edg_segms = 0
- sayw('parsing')
+ sayw("parsing")
sk_label = lyr
- if 'Mask' in lyr:
+ if "Mask" in lyr:
lyr = lyr[:-4]
- #print(lyr)
- keepout=False
- if 'Fill' in lyr or 'KeepOut' in lyr:
- if 'KeepOut' in lyr:
- keepout=True
- lyr = lyr[:2]+'Cu'
- #print(lyr)
-
+ # print(lyr)
+ keepout = False
+ if "Fill" in lyr or "KeepOut" in lyr:
+ if "KeepOut" in lyr:
+ keepout = True
+ lyr = lyr[:2] + "Cu"
+ # print(lyr)
+
for ln in mypcb.gr_line:
- if hasattr(ln, 'layer'):
- k_test=ln.layer
- else:
- k_test=ln.layers
- # if hasattr(ln, 'layer'):
- if lyr in k_test: #ln.layer:
- #say(ln.layer)
- edg_segms+=1
- #elif lyr in ln.layers:
+ k_test = ln.layer if hasattr(ln, "layer") else ln.layers
+ # if hasattr(ln, 'layer'):
+ if lyr in k_test: # ln.layer:
+ # say(ln.layer)
+ edg_segms += 1
+ # elif lyr in ln.layers:
# edg_segms+=1
for ar in mypcb.gr_arc:
- if hasattr(ar, 'layer'):
- k_test=ar.layer
- else:
- k_test=ar.layers
+ k_test = ar.layer if hasattr(ar, "layer") else ar.layers
if lyr in k_test:
- #say(ln.layer)
- edg_segms+=1
+ # say(ln.layer)
+ edg_segms += 1
for lp in mypcb.gr_poly:
- #print(lp)
- #print(lp.layer)
- #print(lp.pts)
- if hasattr(lp, 'layer'):
- k_test=lp.layer
- else:
- k_test=lp.layers
+ # print(lp)
+ # print(lp.layer)
+ # print(lp.pts)
+ k_test = lp.layer if hasattr(lp, "layer") else lp.layers
if lyr in k_test:
- #sayerr(lp.layer)
+ # sayerr(lp.layer)
try:
for p in lp.pts.xy:
- edg_segms+=1
- #sayerr(p)
+ edg_segms += 1
+ # sayerr(p)
except:
for a in lp.pts.arc:
- edg_segms+=1
- #stop
- #edg_segms+=1
+ edg_segms += 1
+ # stop
+ # edg_segms+=1
for bs in mypcb.gr_curve:
- if hasattr(bs, 'layer'):
- k_test=bs.layer
- else:
- k_test=bs.layers
+ k_test = bs.layer if hasattr(bs, "layer") else bs.layers
if lyr in k_test:
- #sayerr(bs.layer)
+ # sayerr(bs.layer)
for p in bs.pts.xy:
- edg_segms+=1
- #edg_segms+=1
+ edg_segms += 1
+ # edg_segms+=1
for r in mypcb.gr_rect:
- if hasattr(r, 'layer'):
- k_test=r.layer
- else:
- k_test=r.layers
+ k_test = r.layer if hasattr(r, "layer") else r.layers
if lyr in k_test:
- #sayerr(bs.layer)
- edg_segms+=4
- #edg_segms+=1
+ # sayerr(bs.layer)
+ edg_segms += 4
+ # edg_segms+=1
for zn in mypcb.zone:
- #print (zn,zn.layer,zn.polygon)
- if hasattr(zn,'layer'):
- zlayer=zn.layer
+ # print (zn,zn.layer,zn.polygon)
+ if hasattr(zn, "layer"):
+ zlayer = zn.layer
else:
- zlayer=zn.layers
- for i,l in enumerate(zlayer):
- l=l.replace('"','')
+ zlayer = zn.layers
+ for i, l in enumerate(zlayer):
+ l = l.replace('"', "")
if isinstance(zlayer, list):
- zlayer[i]=l
+ zlayer[i] = l
else:
- zlayer=l
+ zlayer = l
if not keepout:
- if lyr in zlayer and not hasattr(zn,'keepout'):
- for p in zn.polygon.pts.xy:
- edg_segms+=1
- else:
- #print(zlayer,lyr,lyr in zlayer, hasattr(zn,'keepout'))
- if lyr in zlayer and hasattr(zn,'keepout'):
+ if lyr in zlayer and not hasattr(zn, "keepout"):
for p in zn.polygon.pts.xy:
- edg_segms+=1
-
- sayw(str(edg_segms)+' edge segments')
- #for lp in mypcb.gr_poly: #pcb polylines
+ edg_segms += 1
+ # print(zlayer,lyr,lyr in zlayer, hasattr(zn,'keepout'))
+ elif lyr in zlayer and hasattr(zn, "keepout"):
+ for p in zn.polygon.pts.xy:
+ edg_segms += 1
+
+ sayw(str(edg_segms) + " edge segments")
+ # for lp in mypcb.gr_poly: #pcb polylines
# if lp.layer != 'Edge.Cuts':
# continue
if edg_segms > max_edges_admitted:
- sayerr('too many segments ('+str(edg_segms)+'), skipping sketches & constraints')
+ sayerr("too many segments (" + str(edg_segms) + "), skipping sketches & constraints")
# load_sketch = False
-
+
if load_sketch:
- PCB_Sketch_draft= FreeCAD.activeDocument().addObject('Sketcher::SketchObject','PCB_Sketch_draft')
- FreeCAD.activeDocument().PCB_Sketch_draft.Placement = FreeCAD.Placement(FreeCAD.Vector(0.000000,0.000000,0.000000),FreeCAD.Rotation(0.000000,0.000000,0.000000,1.000000))
-
- #stop
- #sayerr(mypcb.layers['0'])
- if hasattr(mypcb, 'layers'):
- for lynbr in mypcb.layers: #getting layers name
+ FreeCAD.activeDocument().addObject("Sketcher::SketchObject", "PCB_Sketch_draft")
+ FreeCAD.activeDocument().PCB_Sketch_draft.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0.000000, 0.000000, 0.000000),
+ FreeCAD.Rotation(0.000000, 0.000000, 0.000000, 1.000000),
+ )
+
+ # stop
+ # sayerr(mypcb.layers['0'])
+ if hasattr(mypcb, "layers"):
+ for lynbr in mypcb.layers: # getting layers name
if float(lynbr) == Top_lvl:
- LvlTopName=(mypcb.layers['{0}'.format(str(lynbr))][0])
+ LvlTopName = mypcb.layers[f"{str(lynbr)}"][0]
if float(lynbr) == Edge_Cuts_lvl:
- LvlEdgeName=(mypcb.layers['{0}'.format(str(lynbr))][0])
+ (mypcb.layers[f"{str(lynbr)}"][0])
else:
- LvlTopName = 'F.Cu'
- LvlEdgeName = 'Edge.Cuts'
+ LvlTopName = "F.Cu"
# # sayerr(lyr[0])
# # sayerr('top')
- if hasattr(mypcb, 'general'):
- if hasattr(mypcb.general, 'area'):
- say('board area '+str(mypcb.general.area))
- #sayerr('aux_axis_origin' + str(mypcb.setup.aux_axis_origin))
- #stop
+ if hasattr(mypcb, "general") and hasattr(mypcb.general, "area"):
+ say("board area " + str(mypcb.general.area))
+ # sayerr('aux_axis_origin' + str(mypcb.setup.aux_axis_origin))
+ # stop
origin = None
- if hasattr(mypcb, 'setup'):
- if hasattr(mypcb.setup, 'grid_origin'):
- say('grid_origin' + str(mypcb.setup.grid_origin))
- origin = 'grid origin'
- #say(mypcb.setup.aux_axis_origin)
- #xp=mypcb.setup.aux_axis_origin[0]; yp=-mypcb.setup.aux_axis_origin[1]
- elif hasattr(mypcb.setup, 'aux_axis_origin'):
- say('aux_axis_origin' + str(mypcb.setup.aux_axis_origin))
- origin = 'aux origin'
- #say(mypcb.setup.aux_axis_origin)
- #xp=mypcb.setup.aux_axis_origin[0]; yp=-mypcb.setup.aux_axis_origin[1]
+ if hasattr(mypcb, "setup"):
+ if hasattr(mypcb.setup, "grid_origin"):
+ say("grid_origin" + str(mypcb.setup.grid_origin))
+ origin = "grid origin"
+ # say(mypcb.setup.aux_axis_origin)
+ # xp=mypcb.setup.aux_axis_origin[0]; yp=-mypcb.setup.aux_axis_origin[1]
+ elif hasattr(mypcb.setup, "aux_axis_origin"):
+ say("aux_axis_origin" + str(mypcb.setup.aux_axis_origin))
+ origin = "aux origin"
+ # say(mypcb.setup.aux_axis_origin)
+ # xp=mypcb.setup.aux_axis_origin[0]; yp=-mypcb.setup.aux_axis_origin[1]
else:
- say('aux or grid origin not found')
- origin = 'grid origin' #temp workaround for kv6 missing aux origin
+ say("aux or grid origin not found")
+ origin = "grid origin" # temp workaround for kv6 missing aux origin
else:
- say('grid origin not set\ndefault value on top left corner')
- origin = 'grid origin' #temp workaround for kv6 missing aux origin
- #if hasattr(mypcb.setup, 'aux origin'):
+ say("grid origin not set\ndefault value on top left corner")
+ origin = "grid origin" # temp workaround for kv6 missing aux origin
+ # if hasattr(mypcb.setup, 'aux origin'):
# say('aux origin' + str(mypcb.setup.aux_axis_origin))
- #else:
+ # else:
# say('aux origin not used')
## NB use always float() to guarantee number not string!!!
def get_mod_Ref(m):
- #if hasattr(m,'property'):
- if hasattr(m,'property'):
- for p in m.property: #kv8 fp field
- #print(str(p[0]),str(p[1]))
- if 'reference' in str(p[0]).lower():
- # if 'reference' in str(p[1]).lower():
- Ref = str(p[1])
- #print (Ref)
- #stop
- return Ref
- if hasattr(m,'fp_text'):
- for p in m.fp_text: #kv7 fp field
- #print(str(p[0]),str(p[1]))
- if 'reference' in str(p[0]).lower():
- # if 'reference' in str(p[1]).lower():
- Ref = str(p[1])
- return Ref
+ # if hasattr(m,'property'):
+ if hasattr(m, "property"):
+ for p in m.property: # kv8 fp field
+ # print(str(p[0]),str(p[1]))
+ if "reference" in str(p[0]).lower():
+ # if 'reference' in str(p[1]).lower():
+ return str(p[1])
+ # print (Ref)
+ # stop
+ if hasattr(m, "fp_text"):
+ for p in m.fp_text: # kv7 fp field
+ # print(str(p[0]),str(p[1]))
+ if "reference" in str(p[0]).lower():
+ # if 'reference' in str(p[1]).lower():
+ return str(p[1])
+ return None
## try:
## Ref = m.property[0][1] #kv8 fp reference
## #elif hasattr(m,'fp_text'):
## except:
## Ref = m.fp_text[0][1]
## return Ref
-
- def get_mod_dnp(m,rf):
+
+ def get_mod_dnp(m, rf):
# print('reference fp_text',rf)
# (attr through_hole dnp) kv8
- if hasattr(m,'attr'):
- for p in m.attr: #kv8 fp attr if 'dnp' in str(p[0]).lower():
+ if hasattr(m, "attr"):
+ for p in m.attr: # kv8 fp attr if 'dnp' in str(p[0]).lower():
# print (str(p.lower()))
# print(len(p))
- if str(p.lower())== 'dnp':
+ if str(p.lower()) == "dnp":
return True
- if hasattr(m,'fp_text'):
- for t in m.fp_text: #kv7 fp reference
+ if hasattr(m, "fp_text"):
+ for t in m.fp_text: # kv7 fp reference
# print("t[0]",t[0])
- if str(t[0]).lower()=='dnp' or str(t[0]).lower()=='dnf':
- if 'dnp' in str(t[1]).lower() or 'dnf' in str(t[1]).lower():
+ if str(t[0]).lower() == "dnp" or str(t[0]).lower() == "dnf":
+ if "dnp" in str(t[1]).lower() or "dnf" in str(t[1]).lower():
return True
- if str(t[0]).lower()=='user': #kv5 user added text
- #print("t[0], t[1]",t[0], t[1])
- if 'dnp' in str(t[1]).lower() or 'dnf' in str(t[1]).lower():
+ if str(t[0]).lower() == "user": # kv5 user added text
+ # print("t[0], t[1]",t[0], t[1])
+ if "dnp" in str(t[1]).lower() or "dnf" in str(t[1]).lower():
return True
return False
class _ln:
- def __init__(myline, xs,ys,xe,ye):
- myline.start = [xs,ys]
- myline.end = [xe,ye]
-
- ln=_ln(0,0,0,0)
- ply_lines=[]
+ def __init__(myline, xs, ys, xe, ye):
+ myline.start = [xs, ys]
+ myline.end = [xe, ye]
+
+ ln = _ln(0, 0, 0, 0)
+ ply_lines = []
+
def make_gr_line_obj(l, add_ply=None):
global ply_lines
-
- if simu_distance((l.start[0],-l.start[1],0), ((l.end[0],-l.end[1],0))) > edge_tolerance: #non coincident points
- #if (Base.Vector(l.start[0],-l.start[1],0)) != (Base.Vector(l.end[0],-l.end[1],0)): #non coincident points
- line1=Part.Edge(PLine(Base.Vector(l.start[0],-l.start[1],0), Base.Vector(l.end[0],-l.end[1],0)))
- if add_ply==True:
+
+ if (
+ simu_distance((l.start[0], -l.start[1], 0), ((l.end[0], -l.end[1], 0))) > edge_tolerance
+ ): # non coincident points
+ # if (Base.Vector(l.start[0],-l.start[1],0)) != (Base.Vector(l.end[0],-l.end[1],0)): #non coincident points
+ line1 = Part.Edge(PLine(Base.Vector(l.start[0], -l.start[1], 0), Base.Vector(l.end[0], -l.end[1], 0)))
+ if add_ply:
ply_lines.append(line1)
if load_sketch:
- if aux_orig ==1 or grid_orig ==1:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0]-off_x,-l.start[1]-off_y,0), Base.Vector(l.end[0]-off_x,-l.end[1]-off_y,0)))
- PCB_Geo.append(PLine(Base.Vector(l.start[0]-off_x,-l.start[1]-off_y,0), Base.Vector(l.end[0]-off_x,-l.end[1]-off_y,0)))
+ if aux_orig == 1 or grid_orig == 1:
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0]-off_x,-l.start[1]-off_y,0), Base.Vector(l.end[0]-off_x,-l.end[1]-off_y,0)))
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(l.start[0] - off_x, -l.start[1] - off_y, 0),
+ Base.Vector(l.end[0] - off_x, -l.end[1] - off_y, 0),
+ ),
+ )
else:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0],-l.start[1],0), Base.Vector(l.end[0],-l.end[1],0)))
- PCB_Geo.append(PLine(Base.Vector(l.start[0],-l.start[1],0), Base.Vector(l.end[0],-l.end[1],0)))
- edges.append(line1);
- PCB.append(['Line', l.start[0], -l.start[1], l.end[0], -l.end[1]])
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0],-l.start[1],0), Base.Vector(l.end[0],-l.end[1],0)))
+ PCB_Geo.append(PLine(Base.Vector(l.start[0], -l.start[1], 0), Base.Vector(l.end[0], -l.end[1], 0)))
+ edges.append(line1)
+ PCB.append(["Line", l.start[0], -l.start[1], l.end[0], -l.end[1]])
if show_border:
Part.show(line1)
-
- for l in mypcb.gr_line: #pcb lines
- #if l.layer != 'Edge.Cuts':
- if hasattr(l, 'layer'):
- k_test=l.layer
- else:
- k_test=l.layers
+
+ for l in mypcb.gr_line: # pcb lines
+ # if l.layer != 'Edge.Cuts':
+ k_test = l.layer if hasattr(l, "layer") else l.layers
if lyr not in k_test:
- continue
- #edges.append(Part.makeLine(makeVect(l.start),makeVect(l.end)))
- #say(l.start);say(l.end)
- #edge_tolerance_warning
+ continue
+ # edges.append(Part.makeLine(makeVect(l.start),makeVect(l.end)))
+ # say(l.start);say(l.end)
+ # edge_tolerance_warning
make_gr_line_obj(l)
- for r in mypcb.gr_rect: #pcb lines from rect
- #if l.layer != 'Edge.Cuts':
- if hasattr(r, 'layer'):
- k_test=r.layer
- else:
- k_test=r.layers
+ for r in mypcb.gr_rect: # pcb lines from rect
+ # if l.layer != 'Edge.Cuts':
+ k_test = r.layer if hasattr(r, "layer") else r.layers
if lyr not in k_test:
continue
- #segms = [r.start[0],r.start[1]][r.end[0],r.start[1]]
- line1=Part.Edge(PLine(Base.Vector(r.start[0],-r.start[1],0), Base.Vector(r.end[0],-r.start[1],0)))
+ # segms = [r.start[0],r.start[1]][r.end[0],r.start[1]]
+ line1 = Part.Edge(PLine(Base.Vector(r.start[0], -r.start[1], 0), Base.Vector(r.end[0], -r.start[1], 0)))
if load_sketch:
- if aux_orig ==1 or grid_orig ==1:
- PCB_Geo.append(PLine(Base.Vector(r.start[0]-off_x,-r.start[1]-off_y,0), Base.Vector(r.end[0]-off_x,-r.start[1]-off_y,0)))
+ if aux_orig == 1 or grid_orig == 1:
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(r.start[0] - off_x, -r.start[1] - off_y, 0),
+ Base.Vector(r.end[0] - off_x, -r.start[1] - off_y, 0),
+ ),
+ )
else:
- PCB_Geo.append(PLine(Base.Vector(r.start[0],-r.start[1],0), Base.Vector(r.end[0],-r.start[1],0)))
- edges.append(line1);
- PCB.append(['Line', r.end[0], -r.start[1], r.end[0], -r.end[1]])
+ PCB_Geo.append(PLine(Base.Vector(r.start[0], -r.start[1], 0), Base.Vector(r.end[0], -r.start[1], 0)))
+ edges.append(line1)
+ PCB.append(["Line", r.end[0], -r.start[1], r.end[0], -r.end[1]])
if show_border:
Part.show(line1)
- #segms = [r.end[0],r.start[1]][r.end[0],r.end[1]]
- line1=Part.Edge(PLine(Base.Vector(r.end[0],-r.start[1],0), Base.Vector(r.end[0],-r.end[1],0)))
+ # segms = [r.end[0],r.start[1]][r.end[0],r.end[1]]
+ line1 = Part.Edge(PLine(Base.Vector(r.end[0], -r.start[1], 0), Base.Vector(r.end[0], -r.end[1], 0)))
if load_sketch:
- if aux_orig ==1 or grid_orig ==1:
- PCB_Geo.append(PLine(Base.Vector(r.end[0]-off_x,-r.start[1]-off_y,0), Base.Vector(r.end[0]-off_x,-r.end[1]-off_y,0)))
+ if aux_orig == 1 or grid_orig == 1:
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(r.end[0] - off_x, -r.start[1] - off_y, 0),
+ Base.Vector(r.end[0] - off_x, -r.end[1] - off_y, 0),
+ ),
+ )
else:
- PCB_Geo.append(PLine(Base.Vector(r.end[0],-r.start[1],0), Base.Vector(r.end[0],-r.end[1],0)))
- edges.append(line1);
- PCB.append(['Line', r.end[0], -r.start[1], r.end[0], -r.end[1]])
+ PCB_Geo.append(PLine(Base.Vector(r.end[0], -r.start[1], 0), Base.Vector(r.end[0], -r.end[1], 0)))
+ edges.append(line1)
+ PCB.append(["Line", r.end[0], -r.start[1], r.end[0], -r.end[1]])
if show_border:
Part.show(line1)
- #segms = [r.end[0],r.end[1]][r.start[0],r.end[1]]
- line1=Part.Edge(PLine(Base.Vector(r.end[0],-r.end[1],0), Base.Vector(r.start[0],-r.end[1],0)))
+ # segms = [r.end[0],r.end[1]][r.start[0],r.end[1]]
+ line1 = Part.Edge(PLine(Base.Vector(r.end[0], -r.end[1], 0), Base.Vector(r.start[0], -r.end[1], 0)))
if load_sketch:
- if aux_orig ==1 or grid_orig ==1:
- PCB_Geo.append(PLine(Base.Vector(r.end[0]-off_x,-r.end[1]-off_y,0), Base.Vector(r.start[0]-off_x,-r.end[1]-off_y,0)))
+ if aux_orig == 1 or grid_orig == 1:
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(r.end[0] - off_x, -r.end[1] - off_y, 0),
+ Base.Vector(r.start[0] - off_x, -r.end[1] - off_y, 0),
+ ),
+ )
else:
- PCB_Geo.append(PLine(Base.Vector(r.end[0],-r.end[1],0), Base.Vector(r.start[0],-r.end[1],0)))
- edges.append(line1);
- PCB.append(['Line', r.end[0], -r.end[1], r.start[0], -r.end[1]])
+ PCB_Geo.append(PLine(Base.Vector(r.end[0], -r.end[1], 0), Base.Vector(r.start[0], -r.end[1], 0)))
+ edges.append(line1)
+ PCB.append(["Line", r.end[0], -r.end[1], r.start[0], -r.end[1]])
if show_border:
Part.show(line1)
- #segms = [r.start[0],r.end[1]][r.start[0],r.start[1]]
- line1=Part.Edge(PLine(Base.Vector(r.start[0],-r.end[1],0), Base.Vector(r.start[0],-r.start[1],0)))
+ # segms = [r.start[0],r.end[1]][r.start[0],r.start[1]]
+ line1 = Part.Edge(PLine(Base.Vector(r.start[0], -r.end[1], 0), Base.Vector(r.start[0], -r.start[1], 0)))
if load_sketch:
- if aux_orig ==1 or grid_orig ==1:
- PCB_Geo.append(PLine(Base.Vector(r.start[0]-off_x,-r.end[1]-off_y,0), Base.Vector(r.start[0]-off_x,-r.start[1]-off_y,0)))
+ if aux_orig == 1 or grid_orig == 1:
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(r.start[0] - off_x, -r.end[1] - off_y, 0),
+ Base.Vector(r.start[0] - off_x, -r.start[1] - off_y, 0),
+ ),
+ )
else:
- PCB_Geo.append(PLine(Base.Vector(r.start[0],-r.end[1],0), Base.Vector(r.start[0],-r.start[1],0)))
- edges.append(line1);
- PCB.append(['Line', r.start[0], -r.end[1], r.start[0], -r.start[1]])
+ PCB_Geo.append(PLine(Base.Vector(r.start[0], -r.end[1], 0), Base.Vector(r.start[0], -r.start[1], 0)))
+ edges.append(line1)
+ PCB.append(["Line", r.start[0], -r.end[1], r.start[0], -r.start[1]])
if show_border:
Part.show(line1)
k_index = 0
for zn in mypcb.zone:
- #print(zn.layer)
- if hasattr(zn,'layer'):
- zlayer=zn.layer
+ # print(zn.layer)
+ if hasattr(zn, "layer"):
+ zlayer = zn.layer
else:
- zlayer=zn.layers
- for i,l in enumerate(zlayer):
- l=l.replace('"','')
+ zlayer = zn.layers
+ for i, l in enumerate(zlayer):
+ l = l.replace('"', "")
if isinstance(zlayer, list):
- zlayer[i]=l
+ zlayer[i] = l
else:
- zlayer=l
+ zlayer = l
# print(lyr[0],zlayer,lyr[0] in zlayer,lyr[0]+'.Cu' in zlayer)
zl_found = False
for zl in zlayer:
- if lyr[0]+'.Cu' in zlayer:
+ if lyr[0] + ".Cu" in zlayer:
zl_found = True
if not zl_found:
- continue
- if 'Mask' in lyr and 'Mask' not in zlayer:
continue
- #print(zn.polygon.pts.xy)
+ if "Mask" in lyr and "Mask" not in zlayer:
+ continue
+ # print(zn.polygon.pts.xy)
if not keepout:
- if hasattr(zn,'keepout'):
- continue
- else:
- if not hasattr(zn,'keepout'):
+ if hasattr(zn, "keepout"):
continue
- ind = 0
+ elif not hasattr(zn, "keepout"):
+ continue
l = len(zn.polygon.pts.xy)
z_lines = []
- for p in zn.polygon.pts.xy:
+ for ind, p in enumerate(zn.polygon.pts.xy):
if ind == 0:
- line1=Part.Edge(PLine(Base.Vector(zn.polygon.pts.xy[l-1][0],-zn.polygon.pts.xy[l-1][1],0), Base.Vector(zn.polygon.pts.xy[0][0],-zn.polygon.pts.xy[0][1],0)))
- edges.append(line1);
+ line1 = Part.Edge(
+ PLine(
+ Base.Vector(zn.polygon.pts.xy[l - 1][0], -zn.polygon.pts.xy[l - 1][1], 0),
+ Base.Vector(zn.polygon.pts.xy[0][0], -zn.polygon.pts.xy[0][1], 0),
+ ),
+ )
+ edges.append(line1)
if load_sketch:
- if aux_orig ==1 or grid_orig ==1:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0]-off_x,-l.start[1]-off_y,0), Base.Vector(l.end[0]-off_x,-l.end[1]-off_y,0)))
- PCB_Geo.append(PLine(Base.Vector(zn.polygon.pts.xy[l-1][0]-off_x,-zn.polygon.pts.xy[l-1][1]-off_y,0), Base.Vector(zn.polygon.pts.xy[0][0]-off_x,-zn.polygon.pts.xy[0][1]-off_y,0)))
- line2=Part.Edge(PLine(Base.Vector(zn.polygon.pts.xy[l-1][0]-off_x,-zn.polygon.pts.xy[l-1][1]-off_y,0), Base.Vector(zn.polygon.pts.xy[0][0]-off_x,-zn.polygon.pts.xy[0][1]-off_y,0)))
+ if aux_orig == 1 or grid_orig == 1:
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0]-off_x,-l.start[1]-off_y,0), Base.Vector(l.end[0]-off_x,-l.end[1]-off_y,0)))
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(
+ zn.polygon.pts.xy[l - 1][0] - off_x,
+ -zn.polygon.pts.xy[l - 1][1] - off_y,
+ 0,
+ ),
+ Base.Vector(zn.polygon.pts.xy[0][0] - off_x, -zn.polygon.pts.xy[0][1] - off_y, 0),
+ ),
+ )
+ line2 = Part.Edge(
+ PLine(
+ Base.Vector(
+ zn.polygon.pts.xy[l - 1][0] - off_x,
+ -zn.polygon.pts.xy[l - 1][1] - off_y,
+ 0,
+ ),
+ Base.Vector(zn.polygon.pts.xy[0][0] - off_x, -zn.polygon.pts.xy[0][1] - off_y, 0),
+ ),
+ )
else:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0],-l.start[1],0), Base.Vector(l.end[0],-l.end[1],0)))
- PCB_Geo.append(PLine(Base.Vector(zn.polygon.pts.xy[l-1][0],-zn.polygon.pts.xy[l-1][1],0), Base.Vector(zn.polygon.pts.xy[0][0],-zn.polygon.pts.xy[0][1],0)))
- line2=Part.Edge(PLine(Base.Vector(zn.polygon.pts.xy[l-1][0],-zn.polygon.pts.xy[l-1][1],0), Base.Vector(zn.polygon.pts.xy[0][0],-zn.polygon.pts.xy[0][1],0)))
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0],-l.start[1],0), Base.Vector(l.end[0],-l.end[1],0)))
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(zn.polygon.pts.xy[l - 1][0], -zn.polygon.pts.xy[l - 1][1], 0),
+ Base.Vector(zn.polygon.pts.xy[0][0], -zn.polygon.pts.xy[0][1], 0),
+ ),
+ )
+ line2 = Part.Edge(
+ PLine(
+ Base.Vector(zn.polygon.pts.xy[l - 1][0], -zn.polygon.pts.xy[l - 1][1], 0),
+ Base.Vector(zn.polygon.pts.xy[0][0], -zn.polygon.pts.xy[0][1], 0),
+ ),
+ )
z_lines.append(line2)
else:
- line1=Part.Edge(PLine(Base.Vector(zn.polygon.pts.xy[ind-1][0],-zn.polygon.pts.xy[ind-1][1],0), Base.Vector(zn.polygon.pts.xy[ind][0],-zn.polygon.pts.xy[ind][1],0)))
- edges.append(line1);
+ line1 = Part.Edge(
+ PLine(
+ Base.Vector(zn.polygon.pts.xy[ind - 1][0], -zn.polygon.pts.xy[ind - 1][1], 0),
+ Base.Vector(zn.polygon.pts.xy[ind][0], -zn.polygon.pts.xy[ind][1], 0),
+ ),
+ )
+ edges.append(line1)
if load_sketch:
- if aux_orig ==1 or grid_orig ==1:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0]-off_x,-l.start[1]-off_y,0), Base.Vector(l.end[0]-off_x,-l.end[1]-off_y,0)))
- PCB_Geo.append(PLine(Base.Vector(zn.polygon.pts.xy[ind-1][0]-off_x,-zn.polygon.pts.xy[ind-1][1]-off_y,0), Base.Vector(zn.polygon.pts.xy[ind][0]-off_x,-zn.polygon.pts.xy[ind][1]-off_y,0)))
- line2=Part.Edge(PLine(Base.Vector(zn.polygon.pts.xy[ind-1][0]-off_x,-zn.polygon.pts.xy[ind-1][1]-off_y,0), Base.Vector(zn.polygon.pts.xy[ind][0]-off_x,-zn.polygon.pts.xy[ind][1]-off_y,0)))
+ if aux_orig == 1 or grid_orig == 1:
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0]-off_x,-l.start[1]-off_y,0), Base.Vector(l.end[0]-off_x,-l.end[1]-off_y,0)))
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(
+ zn.polygon.pts.xy[ind - 1][0] - off_x,
+ -zn.polygon.pts.xy[ind - 1][1] - off_y,
+ 0,
+ ),
+ Base.Vector(zn.polygon.pts.xy[ind][0] - off_x, -zn.polygon.pts.xy[ind][1] - off_y, 0),
+ ),
+ )
+ line2 = Part.Edge(
+ PLine(
+ Base.Vector(
+ zn.polygon.pts.xy[ind - 1][0] - off_x,
+ -zn.polygon.pts.xy[ind - 1][1] - off_y,
+ 0,
+ ),
+ Base.Vector(zn.polygon.pts.xy[ind][0] - off_x, -zn.polygon.pts.xy[ind][1] - off_y, 0),
+ ),
+ )
else:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0],-l.start[1],0), Base.Vector(l.end[0],-l.end[1],0)))
- PCB_Geo.append(PLine(Base.Vector(zn.polygon.pts.xy[ind-1][0],-zn.polygon.pts.xy[ind-1][1],0), Base.Vector(zn.polygon.pts.xy[ind][0],-zn.polygon.pts.xy[ind][1],0)))
- line2=Part.Edge(PLine(Base.Vector(zn.polygon.pts.xy[ind-1][0],-zn.polygon.pts.xy[ind-1][1],0), Base.Vector(zn.polygon.pts.xy[ind][0],-zn.polygon.pts.xy[ind][1],0)))
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0],-l.start[1],0), Base.Vector(l.end[0],-l.end[1],0)))
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(zn.polygon.pts.xy[ind - 1][0], -zn.polygon.pts.xy[ind - 1][1], 0),
+ Base.Vector(zn.polygon.pts.xy[ind][0], -zn.polygon.pts.xy[ind][1], 0),
+ ),
+ )
+ line2 = Part.Edge(
+ PLine(
+ Base.Vector(zn.polygon.pts.xy[ind - 1][0], -zn.polygon.pts.xy[ind - 1][1], 0),
+ Base.Vector(zn.polygon.pts.xy[ind][0], -zn.polygon.pts.xy[ind][1], 0),
+ ),
+ )
z_lines.append(line2)
- ind+=1
Draft.makeSketch(z_lines)
ndsk = FreeCAD.ActiveDocument.ActiveObject
- ndsk.Label = sk_label + '_' + str(k_index)
- ndsk.ViewObject.LineColor = (1.00,1.00,1.00)
- ndsk.ViewObject.PointColor = (1.00,1.00,1.00)
+ ndsk.Label = sk_label + "_" + str(k_index)
+ ndsk.ViewObject.LineColor = (1.00, 1.00, 1.00)
+ ndsk.ViewObject.PointColor = (1.00, 1.00, 1.00)
k_index += 1
- #closing edge
- def make_gr_arc_obj (a,pa):
+ # closing edge
+
+ def make_gr_arc_obj(a, pa):
global load_sketch, aux_orig, grid_orig, ply_lines
-
+
[xs, ys] = a.start
[x1, y1] = a.end
try:
- if hasattr (a, 'mid'):
- [xm, ym] = a.mid
- arc1 = Part.Edge(Part.Arc(Base.Vector(xs,-ys,0),Base.Vector(xm,-ym,0),Base.Vector(x1,-y1,0)))
- curve = arc1.Curve.AngleXU/pi*180
- #curve = arc1.AngleXU/pi*180
- #print(curve)
+ if hasattr(a, "mid"):
+ [xm, ym] = a.mid
+ arc1 = Part.Edge(Part.Arc(Base.Vector(xs, -ys, 0), Base.Vector(xm, -ym, 0), Base.Vector(x1, -y1, 0)))
+ curve = arc1.Curve.AngleXU / pi * 180
+ # curve = arc1.AngleXU/pi*180
+ # print(curve)
if curve > 0:
- curve = -1*curve
- #print('inverting')
- #arc1.reverse();
- #Part.show(arc1);print(curve) #;stop
+ curve = -1 * curve
+ # print('inverting')
+ # arc1.reverse();
+ # Part.show(arc1);print(curve) #;stop
[x2, y2] = rotPoint2([x1, y1], [xs, ys], curve)
else:
curve = a.angle
[x2, y2] = rotPoint2([x1, y1], [xs, ys], curve)
- arc1 = Part.Edge(Part.Arc(Base.Vector(x2,-y2,0),mid_point(Base.Vector(x2,-y2,0),Base.Vector(x1,-y1,0),curve),Base.Vector(x1,-y1,0)))
+ arc1 = Part.Edge(
+ Part.Arc(
+ Base.Vector(x2, -y2, 0),
+ mid_point(Base.Vector(x2, -y2, 0), Base.Vector(x1, -y1, 0), curve),
+ Base.Vector(x1, -y1, 0),
+ ),
+ )
# if curve>0:
# arc = Part.makeCircle(r,center,Vector(0,0,1),a-angle,a)
# arc.reverse();
# else:
# arc = Part.makeCircle(r,center,Vector(0,0,1),a,a-angle)
Cntr = arc1.Curve.Center
- #Cntr = arc1.Center
- cx=Cntr.x;cy=Cntr.y
- #print cx,cy
+ # Cntr = arc1.Center
+ cx = Cntr.x
+ cy = Cntr.y
+ # print cx,cy
r = arc1.Curve.Radius
- #r = arc1.Radius
- #r=arcRadius(xs, ys, x1, y1, curve)
- #sa = arc1.Curve.FirstAngle
- #ea = arc1.Curve.LastAngle
- #sa,ea = arcAngles2(xs, ys, x1, y1, cx, cy, curve)
- sa,ea = arcAngles2(arc1,curve)
- #print sa,';',ea
- #print mid_point(Base.Vector(x2,-y2,0),Base.Vector(x1,-y1,0),curve)
- #[mx,my]=arcMidPoint([xs,ys], [x1,y1], curve)
- #c=arc1.Curve.Center
- #print c
- #App.ActiveDocument.PCB_SketchN.addGeometry(Part.Arc(Base.Vector(x2,-y2,0),mid_point(Base.Vector(x2,-y2,0),Base.Vector(x1,-y1,0),curve),Base.Vector(x1,-y1,0)))
+ # r = arc1.Radius
+ # r=arcRadius(xs, ys, x1, y1, curve)
+ # sa = arc1.Curve.FirstAngle
+ # ea = arc1.Curve.LastAngle
+ # sa,ea = arcAngles2(xs, ys, x1, y1, cx, cy, curve)
+ sa, ea = arcAngles2(arc1, curve)
+ # print sa,';',ea
+ # print mid_point(Base.Vector(x2,-y2,0),Base.Vector(x1,-y1,0),curve)
+ # [mx,my]=arcMidPoint([xs,ys], [x1,y1], curve)
+ # c=arc1.Curve.Center
+ # print c
+ # App.ActiveDocument.PCB_SketchN.addGeometry(Part.Arc(Base.Vector(x2,-y2,0),mid_point(Base.Vector(x2,-y2,0),Base.Vector(x1,-y1,0),curve),Base.Vector(x1,-y1,0)))
if load_sketch:
- line1=""
- if aux_orig ==1 or grid_orig ==1:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx-off_x,cy-off_y,0),FreeCAD.Vector(0,0,1),r),sa,ea),False)
- #PCB_Geo.append(Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx-off_x,cy-off_y,0),FreeCAD.Vector(0,0,1),r),sa,ea))
- if hasattr (a, 'mid'):
- PCB_Geo.append(Part.ArcOfCircle(kicad_parser.makeVect([a.start[0]-off_x,a.start[1]+off_y]),
- kicad_parser.makeVect([a.mid[0]-off_x,a.mid[1]+off_y]),
- kicad_parser.makeVect([a.end[0]-off_x,a.end[1]+off_y])))
+ line1 = ""
+ if aux_orig == 1 or grid_orig == 1:
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx-off_x,cy-off_y,0),FreeCAD.Vector(0,0,1),r),sa,ea),False)
+ # PCB_Geo.append(Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx-off_x,cy-off_y,0),FreeCAD.Vector(0,0,1),r),sa,ea))
+ if hasattr(a, "mid"):
+ PCB_Geo.append(
+ Part.ArcOfCircle(
+ kicad_parser.makeVect([a.start[0] - off_x, a.start[1] + off_y]),
+ kicad_parser.makeVect([a.mid[0] - off_x, a.mid[1] + off_y]),
+ kicad_parser.makeVect([a.end[0] - off_x, a.end[1] + off_y]),
+ ),
+ )
# print('a.start=',a.start,'a.mid=',a.mid,'a.end=',a.end, 'off_x=',off_x, 'off_y=',off_y)
# Part.show(Part.ArcOfCircle(kicad_parser.makeVect([a.start[0]-off_x,a.start[1]+off_y]),
# kicad_parser.makeVect([a.mid[0]-off_x,a.mid[1]+off_y]),
# kicad_parser.makeVect([a.end[0]-off_x,a.end[1]+off_y])).toShape())
# print(pa)
- if pa!="":
- if not(pa.end == a.start):
- #PCB_Geo.append(PLine(Base.Vector(r.end[0]-off_x,-r.end[1]-off_y,0), Base.Vector(r.start[0]-off_x,-r.end[1]-off_y,0)))
+ if pa != "":
+ if pa.end != a.start:
+ # PCB_Geo.append(PLine(Base.Vector(r.end[0]-off_x,-r.end[1]-off_y,0), Base.Vector(r.start[0]-off_x,-r.end[1]-off_y,0)))
# PCB_Geo.append(PLine(kicad_parser.makeVect([pa.end[0]-off_x,pa.end[1]+off_y]),(kicad_parser.makeVect([a.start[0]-off_x,a.start[1]+off_y]))))
- ln=_ln(0,0,0,0) #class _ln
- #ln.start = [pa.end[0]-off_x,pa.end[1]+off_y]
- ln.start = [pa.end[0],pa.end[1]]
- #ln.end = [a.start[0]-off_x,a.start[1]+off_y]
- ln.end = [a.start[0],a.start[1]]
- make_gr_line_obj(ln,add_ply=True)
+ ln = _ln(0, 0, 0, 0) # class _ln
+ # ln.start = [pa.end[0]-off_x,pa.end[1]+off_y]
+ ln.start = [pa.end[0], pa.end[1]]
+ # ln.end = [a.start[0]-off_x,a.start[1]+off_y]
+ ln.end = [a.start[0], a.start[1]]
+ make_gr_line_obj(ln, add_ply=True)
# line1=Part.Edge(PLine(kicad_parser.makeVect([pa.end[0]-off_x,pa.end[1]+off_y]),PLine(kicad_parser.makeVect([a.start[0]-off_x,a.start[1]+off_y]))))
else:
- PCB_Geo.append(Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx-off_x,cy-off_y,0),FreeCAD.Vector(0,0,1),r),sa,ea))
+ PCB_Geo.append(
+ Part.ArcOfCircle(
+ Part.Circle(FreeCAD.Vector(cx - off_x, cy - off_y, 0), FreeCAD.Vector(0, 0, 1), r),
+ sa,
+ ea,
+ ),
+ )
+ elif hasattr(a, "mid"):
+ PCB_Geo.append(
+ Part.ArcOfCircle(
+ kicad_parser.makeVect(a.start),
+ kicad_parser.makeVect(a.mid),
+ kicad_parser.makeVect(a.end),
+ ),
+ )
+ if pa != "" and pa.end != a.start:
+ # PCB_Geo.append(PLine(kicad_parser.makeVect(pa.end),PLine(kicad_parser.makeVect(a.start)),0))
+ # line1=Part.Edge(PLine(kicad_parser.makeVect(pa.end),PLine(kicad_parser.makeVect(a.start))))
+ ln = _ln(0, 0, 0, 0) # class _ln
+ ln.start = [pa.end[0], pa.end[1]]
+ ln.end = [a.start[0], a.start[1]]
+ make_gr_line_obj(ln, add_ply=True)
else:
- if hasattr (a, 'mid'):
- PCB_Geo.append(Part.ArcOfCircle(kicad_parser.makeVect(a.start),
- kicad_parser.makeVect(a.mid),
- kicad_parser.makeVect(a.end)))
- if pa!="":
- if not(pa.end == a.start):
- # PCB_Geo.append(PLine(kicad_parser.makeVect(pa.end),PLine(kicad_parser.makeVect(a.start)),0))
- # line1=Part.Edge(PLine(kicad_parser.makeVect(pa.end),PLine(kicad_parser.makeVect(a.start))))
- ln=_ln(0,0,0,0) #class _ln
- ln.start = [pa.end[0],pa.end[1]]
- ln.end = [a.start[0],a.start[1]]
- make_gr_line_obj(ln,add_ply=True)
- else:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx,cy,0),FreeCAD.Vector(0,0,1),r),sa,ea),False)
- PCB_Geo.append(Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx,cy,0),FreeCAD.Vector(0,0,1),r),sa,ea))
- #mp=mid_point(Base.Vector(x2,-y2,0),Base.Vector(x1,-y1,0),curve)
- #msg1= "App.ActiveDocument.PCB_SketchN.addGeometry(Part.Arc(Base.Vector({0},-{1},0),{4},Base.Vector({2},-{3},0)))".format(x2,y2,x1,y1,mp)
- #print msg1
- #App.ActiveDocument.Sketch.addGeometry(Part.Arc(App.Vector(33.0,66.5,0.3),App.Vector(32.85857864376269,66.44142135623731,0.3),App.Vector(32.8,66.3,0.3)))
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx,cy,0),FreeCAD.Vector(0,0,1),r),sa,ea),False)
+ PCB_Geo.append(
+ Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx, cy, 0), FreeCAD.Vector(0, 0, 1), r), sa, ea),
+ )
+ # mp=mid_point(Base.Vector(x2,-y2,0),Base.Vector(x1,-y1,0),curve)
+ # msg1= "App.ActiveDocument.PCB_SketchN.addGeometry(Part.Arc(Base.Vector({0},-{1},0),{4},Base.Vector({2},-{3},0)))".format(x2,y2,x1,y1,mp)
+ # print msg1
+ # App.ActiveDocument.Sketch.addGeometry(Part.Arc(App.Vector(33.0,66.5,0.3),App.Vector(32.85857864376269,66.44142135623731,0.3),App.Vector(32.8,66.3,0.3)))
edges.append(arc1)
- if line1!="":
+ if line1 != "":
edges.append(line1)
- PCB.append(['Arc',x1, -y1, x2, -y2, curve])
+ PCB.append(["Arc", x1, -y1, x2, -y2, curve])
if show_border:
Part.show(arc1)
- if line1!="":
+ if line1 != "":
Part.show(line1)
except:
- sayw('skipping wrong geometry')
- pass
+ sayw("skipping wrong geometry")
# k_index = 0
- for lp in mypcb.gr_poly: #pcb polylines
- if hasattr(lp, 'layer'):
- k_test=lp.layer
- else:
- k_test=lp.layers
+ for lp in mypcb.gr_poly: # pcb polylines
+ k_test = lp.layer if hasattr(lp, "layer") else lp.layers
if lyr not in k_test:
- # if lp.layer != 'Edge.Cuts':
+ # if lp.layer != 'Edge.Cuts':
continue
ply_lines = []
ind = 0
- if hasattr(lp.pts,"xy"):
+ if hasattr(lp.pts, "xy"):
l = len(lp.pts.xy)
for p in lp.pts.xy:
if ind == 0:
- line1=Part.Edge(PLine(Base.Vector(lp.pts.xy[l-1][0],-lp.pts.xy[l-1][1],0), Base.Vector(lp.pts.xy[0][0],-lp.pts.xy[0][1],0)))
- edges.append(line1);
+ line1 = Part.Edge(
+ PLine(
+ Base.Vector(lp.pts.xy[l - 1][0], -lp.pts.xy[l - 1][1], 0),
+ Base.Vector(lp.pts.xy[0][0], -lp.pts.xy[0][1], 0),
+ ),
+ )
+ edges.append(line1)
if load_sketch:
- if aux_orig ==1 or grid_orig ==1:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0]-off_x,-l.start[1]-off_y,0), Base.Vector(l.end[0]-off_x,-l.end[1]-off_y,0)))
- PCB_Geo.append(PLine(Base.Vector(lp.pts.xy[l-1][0]-off_x,-lp.pts.xy[l-1][1]-off_y,0), Base.Vector(lp.pts.xy[0][0]-off_x,-lp.pts.xy[0][1]-off_y,0)))
- if k_test != 'Edge.Cuts':
- line2=Part.Edge(PLine(Base.Vector(lp.pts.xy[l-1][0]-off_x,-lp.pts.xy[l-1][1]-off_y,0), Base.Vector(lp.pts.xy[0][0]-off_x,-lp.pts.xy[0][1]-off_y,0)))
+ if aux_orig == 1 or grid_orig == 1:
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0]-off_x,-l.start[1]-off_y,0), Base.Vector(l.end[0]-off_x,-l.end[1]-off_y,0)))
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(lp.pts.xy[l - 1][0] - off_x, -lp.pts.xy[l - 1][1] - off_y, 0),
+ Base.Vector(lp.pts.xy[0][0] - off_x, -lp.pts.xy[0][1] - off_y, 0),
+ ),
+ )
+ if k_test != "Edge.Cuts":
+ line2 = Part.Edge(
+ PLine(
+ Base.Vector(lp.pts.xy[l - 1][0] - off_x, -lp.pts.xy[l - 1][1] - off_y, 0),
+ Base.Vector(lp.pts.xy[0][0] - off_x, -lp.pts.xy[0][1] - off_y, 0),
+ ),
+ )
else:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0],-l.start[1],0), Base.Vector(l.end[0],-l.end[1],0)))
- PCB_Geo.append(PLine(Base.Vector(lp.pts.xy[l-1][0],-lp.pts.xy[l-1][1],0), Base.Vector(lp.pts.xy[0][0],-lp.pts.xy[0][1],0)))
- if k_test != 'Edge.Cuts':
- line2=Part.Edge(PLine(Base.Vector(lp.pts.xy[l-1][0],-lp.pts.xy[l-1][1],0), Base.Vector(lp.pts.xy[0][0],-lp.pts.xy[0][1],0)))
- if k_test != 'Edge.Cuts':
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0],-l.start[1],0), Base.Vector(l.end[0],-l.end[1],0)))
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(lp.pts.xy[l - 1][0], -lp.pts.xy[l - 1][1], 0),
+ Base.Vector(lp.pts.xy[0][0], -lp.pts.xy[0][1], 0),
+ ),
+ )
+ if k_test != "Edge.Cuts":
+ line2 = Part.Edge(
+ PLine(
+ Base.Vector(lp.pts.xy[l - 1][0], -lp.pts.xy[l - 1][1], 0),
+ Base.Vector(lp.pts.xy[0][0], -lp.pts.xy[0][1], 0),
+ ),
+ )
+ if k_test != "Edge.Cuts":
ply_lines.append(line2)
else:
- line1=Part.Edge(PLine(Base.Vector(lp.pts.xy[ind-1][0],-lp.pts.xy[ind-1][1],0), Base.Vector(lp.pts.xy[ind][0],-lp.pts.xy[ind][1],0)))
- edges.append(line1);
+ line1 = Part.Edge(
+ PLine(
+ Base.Vector(lp.pts.xy[ind - 1][0], -lp.pts.xy[ind - 1][1], 0),
+ Base.Vector(lp.pts.xy[ind][0], -lp.pts.xy[ind][1], 0),
+ ),
+ )
+ edges.append(line1)
if load_sketch:
- if aux_orig ==1 or grid_orig ==1:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0]-off_x,-l.start[1]-off_y,0), Base.Vector(l.end[0]-off_x,-l.end[1]-off_y,0)))
- PCB_Geo.append(PLine(Base.Vector(lp.pts.xy[ind-1][0]-off_x,-lp.pts.xy[ind-1][1]-off_y,0), Base.Vector(lp.pts.xy[ind][0]-off_x,-lp.pts.xy[ind][1]-off_y,0)))
- if k_test != 'Edge.Cuts':
- line2=Part.Edge(PLine(Base.Vector(lp.pts.xy[ind-1][0]-off_x,-lp.pts.xy[ind-1][1]-off_y,0), Base.Vector(lp.pts.xy[ind][0]-off_x,-lp.pts.xy[ind][1]-off_y,0)))
+ if aux_orig == 1 or grid_orig == 1:
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0]-off_x,-l.start[1]-off_y,0), Base.Vector(l.end[0]-off_x,-l.end[1]-off_y,0)))
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(lp.pts.xy[ind - 1][0] - off_x, -lp.pts.xy[ind - 1][1] - off_y, 0),
+ Base.Vector(lp.pts.xy[ind][0] - off_x, -lp.pts.xy[ind][1] - off_y, 0),
+ ),
+ )
+ if k_test != "Edge.Cuts":
+ line2 = Part.Edge(
+ PLine(
+ Base.Vector(lp.pts.xy[ind - 1][0] - off_x, -lp.pts.xy[ind - 1][1] - off_y, 0),
+ Base.Vector(lp.pts.xy[ind][0] - off_x, -lp.pts.xy[ind][1] - off_y, 0),
+ ),
+ )
else:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0],-l.start[1],0), Base.Vector(l.end[0],-l.end[1],0)))
- PCB_Geo.append(PLine(Base.Vector(lp.pts.xy[ind-1][0],-lp.pts.xy[ind-1][1],0), Base.Vector(lp.pts.xy[ind][0],-lp.pts.xy[ind][1],0)))
- if k_test != 'Edge.Cuts':
- line2=Part.Edge(PLine(Base.Vector(lp.pts.xy[ind-1][0],-lp.pts.xy[ind-1][1],0), Base.Vector(lp.pts.xy[ind][0],-lp.pts.xy[ind][1],0)))
- if k_test != 'Edge.Cuts':
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(PLine(Base.Vector(l.start[0],-l.start[1],0), Base.Vector(l.end[0],-l.end[1],0)))
+ PCB_Geo.append(
+ PLine(
+ Base.Vector(lp.pts.xy[ind - 1][0], -lp.pts.xy[ind - 1][1], 0),
+ Base.Vector(lp.pts.xy[ind][0], -lp.pts.xy[ind][1], 0),
+ ),
+ )
+ if k_test != "Edge.Cuts":
+ line2 = Part.Edge(
+ PLine(
+ Base.Vector(lp.pts.xy[ind - 1][0], -lp.pts.xy[ind - 1][1], 0),
+ Base.Vector(lp.pts.xy[ind][0], -lp.pts.xy[ind][1], 0),
+ ),
+ )
+ if k_test != "Edge.Cuts":
ply_lines.append(line2)
- ind+=1
- else: # hasattr(params.pts,"arc")
- pa=""
- a0=""
+ ind += 1
+ else: # hasattr(params.pts,"arc")
+ pa = ""
+ a0 = ""
for a in lp.pts.arc:
- if a0=="":
- a0=a
- make_gr_arc_obj(a,pa)
+ if a0 == "":
+ a0 = a
+ make_gr_arc_obj(a, pa)
pa = a
- if a0.start!=a.end: # and len(lp.pts.arc)>2:
- print('edge to add')
- ln.start=a.end
- ln.end=a0.start
- make_gr_line_obj(ln,add_ply=True)
-
- #print(lp.layer)
- if 0: #'Edge.Cuts' not in lp.layer:
- Draft.makeSketch(ply_lines) #TBD allow gr_arcs also on different layers
+ if a0.start != a.end: # and len(lp.pts.arc)>2:
+ print("edge to add")
+ ln.start = a.end
+ ln.end = a0.start
+ make_gr_line_obj(ln, add_ply=True)
+
+ # print(lp.layer)
+ if 0: #'Edge.Cuts' not in lp.layer:
+ Draft.makeSketch(ply_lines) # TBD allow gr_arcs also on different layers
ndsk = FreeCAD.ActiveDocument.ActiveObject
- ndsk.Label = sk_label + '_Poly_' + str(k_index)
- ndsk.ViewObject.LineColor = (1.00,1.00,1.00)
- ndsk.ViewObject.PointColor = (1.00,1.00,1.00)
+ ndsk.Label = sk_label + "_Poly_" + str(k_index)
+ ndsk.ViewObject.LineColor = (1.00, 1.00, 1.00)
+ ndsk.ViewObject.PointColor = (1.00, 1.00, 1.00)
k_index += 1
- #closing edge
+ # closing edge
- #bsplines
+ # bsplines
for bs in mypcb.gr_curve:
# if bs.layer != 'Edge.Cuts':
- if hasattr(bs, 'layer'):
- k_test=bs.layer
- else:
- k_test=bs.layers
+ k_test = bs.layer if hasattr(bs, "layer") else bs.layers
if lyr not in k_test:
continue
ind = 0
- #sayerr(bs.layer)
+ # sayerr(bs.layer)
poles = []
for p in bs.pts.xy:
# sayerr(p)
- poles.append(FreeCAD.Vector (p[0]-off_x,-p[1]-off_y,0.0))
+ poles.append(FreeCAD.Vector(p[0] - off_x, -p[1] - off_y, 0.0))
# sayerr(poles)
- spline=Part.BSplineCurve()
+ spline = Part.BSplineCurve()
spline.buildFromPoles(poles, False, 3)
edges.append(Part.Edge(spline))
- #stop
- #edges.append(Part.Edge(spline2))
+ # stop
+ # edges.append(Part.Edge(spline2))
# Part.show(spline.toShape())
# import kicadStepUptools; import importlib; importlib.reload(kicadStepUptools);kicadStepUptools.open(u"C:/Temp/bspline.kicad_pcb")
if load_sketch:
- if aux_orig ==1 or grid_orig ==1:
+ if aux_orig == 1 or grid_orig == 1:
PCB_Geo.append(spline)
# pi = 0
- #for p in bs.pts.xy:
+ # for p in bs.pts.xy:
# if (pi == 1) or (pi == 2):
# PCB_Geo.append(Part.Circle (FreeCAD.Vector(p[0]-off_x, -p[1]-off_y), FreeCAD.Vector(0, 0, 1), 0.5))
# l = len(PCB_Geo)
@@ -12549,7 +13517,7 @@ def make_gr_arc_obj (a,pa):
# PCB_Geo[l-1].Construction = True
# #PCB_Geo.append(Part.Circle (0.5, Base.Vector(p[0]-off_x, -p[1]-off_y, 0.0), Base.Vector(1,0,0)))
# pi+=1
- #for p in bs.pts.xy:
+ # for p in bs.pts.xy:
# if (pi == 0) or (pi == 4):
# PCB_Geo.append(Part.Point (FreeCAD.Vector(p[0]-off_x, -p[1]-off_y, 0.0)))
# l = len(PCB_Geo)
@@ -12563,89 +13531,89 @@ def make_gr_arc_obj (a,pa):
# for p in bs.pts.xy:
# if (pi == 1) or (pi == 2):
# PCB_Geo.append(Part.makeCircle (0.5, Base.Vector(p[0]-off_x, -p[1]-off_y, 0.0), Base.Vector(1,0,0)))
- # pi+=1
- #stop
+ # pi+=1
+ # stop
## NB use always float() to guarantee number not string!!!
- pa=""
- for a in mypcb.gr_arc: #pcb arcs
+ pa = ""
+ for a in mypcb.gr_arc: # pcb arcs
# if a.layer != 'Edge.Cuts':
- if hasattr(a, 'layer'):
- k_test=a.layer
- else:
- k_test=a.layers
+ k_test = a.layer if hasattr(a, "layer") else a.layers
if lyr not in k_test:
continue
# for gr_arc, 'start' is actual the center, and 'end' is the start
- #edges.append(makeArc(makeVect(l.start),makeVect(l.end),l.angle))
- make_gr_arc_obj(a,pa)
+ # edges.append(makeArc(makeVect(l.start),makeVect(l.end),l.angle))
+ make_gr_arc_obj(a, pa)
# pa=a
-
+
## NB use always float() to guarantee number not string!!!
- for c in mypcb.gr_circle: #pcb circles
+ for c in mypcb.gr_circle: # pcb circles
# if c.layer != 'Edge.Cuts':
- if hasattr(c, 'layer'):
- k_test=c.layer
- else:
- k_test=c.layers
+ k_test = c.layer if hasattr(c, "layer") else c.layers
if lyr not in k_test:
continue
[xs, ys] = c.center
[x1, y1] = c.end
- ys=-ys;y1=-y1
- #say(xs); say(ys)
+ ys = -ys
+ y1 = -y1
+ # say(xs); say(ys)
r = sqrt((xs - x1) ** 2 + (ys - y1) ** 2)
- #sayerr(r)
+ # sayerr(r)
if r != 0.0:
- circle1=Part.Edge(Part.Circle(Base.Vector(xs, ys,0), Base.Vector(0, 0, 1), r))
+ circle1 = Part.Edge(Part.Circle(Base.Vector(xs, ys, 0), Base.Vector(0, 0, 1), r))
if load_sketch:
- if aux_orig ==1 or grid_orig ==1:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(Part.Circle(Base.Vector(xs-off_x, ys-off_y,0), Base.Vector(0, 0, 1), r))
- PCB_Geo.append(Part.Circle(Base.Vector(xs-off_x, ys-off_y,0), Base.Vector(0, 0, 1), r))
+ if aux_orig == 1 or grid_orig == 1:
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(Part.Circle(Base.Vector(xs-off_x, ys-off_y,0), Base.Vector(0, 0, 1), r))
+ PCB_Geo.append(Part.Circle(Base.Vector(xs - off_x, ys - off_y, 0), Base.Vector(0, 0, 1), r))
else:
- #FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(Part.Circle(Base.Vector(xs, ys,0), Base.Vector(0, 0, 1), r))
- PCB_Geo.append(Part.Circle(Base.Vector(xs, ys,0), Base.Vector(0, 0, 1), r))
+ # FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(Part.Circle(Base.Vector(xs, ys,0), Base.Vector(0, 0, 1), r))
+ PCB_Geo.append(Part.Circle(Base.Vector(xs, ys, 0), Base.Vector(0, 0, 1), r))
if show_border:
Part.show(circle1)
- circle1=Part.Wire(circle1)
- circle1=Part.Face(circle1)
+ circle1 = Part.Wire(circle1)
+ circle1 = Part.Face(circle1)
if show_shapes:
Part.show(circle1)
- say('2d circle closed path')
+ say("2d circle closed path")
PCBs.append(circle1)
- PCB.append(['Circle', xs, ys, r])
+ PCB.append(["Circle", xs, ys, r])
else:
- sayw('circle with 0 radius at '+str(c.center))
+ sayw("circle with 0 radius at " + str(c.center))
- #say(PCBs)
+ # say(PCBs)
get_time()
- say('parsing&building time ' +str(round(running_time-t0,3)))
+ say("parsing&building time " + str(round(running_time - t0, 3)))
if 0:
new_cpy_skt = FreeCAD.ActiveDocument.copyObject(FreeCAD.ActiveDocument.PCB_Sketch_draft, True)
- FreeCAD.ActiveDocument.addObject("Part::Face", "Face_PCB_Sketch_draft").Sources = (new_cpy_skt, )
+ FreeCAD.ActiveDocument.addObject("Part::Face", "Face_PCB_Sketch_draft").Sources = (new_cpy_skt,)
FreeCAD.ActiveDocument.recompute()
s_PCB_Sketch_draft = FreeCAD.ActiveDocument.getObject("Face_PCB_Sketch_draft").Shape
Part.show(s_PCB_Sketch_draft)
FreeCAD.ActiveDocument.removeObject("Face_PCB_Sketch_draft")
FreeCAD.ActiveDocument.recompute()
-
- make_face = True #getting PCB from Sketch
- use_PCB_Sketch_E = False #getting PCB from Sketch and Fp Edges
+
+ make_face = True # getting PCB from Sketch
+ use_PCB_Sketch_E = False # getting PCB from Sketch and Fp Edges
dont_use_constraints = False
create_pcb_from_edges = False
create_pcb_basic = False
fcv = getFCversion()
- if fcv[0]==0 and fcv[1] <17:
- make_face = False
- create_pcb_from_edges =True
+ if fcv[0] == 0 and fcv[1] < 17:
+ make_face = False
+ create_pcb_from_edges = True
if edg_segms > max_edges_admitted:
- #sayerr('too many segments, skipping sketches & constraints')
- sayerr('too many segments, skipping ALL constraints')
+ # sayerr('too many segments, skipping sketches & constraints')
+ sayerr("too many segments, skipping ALL constraints")
if FreeCAD.GuiUp:
from PySide import QtGui
+
QtGui.QApplication.restoreOverrideCursor()
d = QtGui.QMessageBox()
- d.setText("""Warning: High number of entities to join (> """+str(max_edges_admitted)+""")
Constraints will not be applied to PCB Sketch""")
+ d.setText(
+ """Warning: High number of entities to join (> """
+ + str(max_edges_admitted)
+ + """)
Constraints will not be applied to PCB Sketch""",
+ )
d.setInformativeText("This might take a long time or even freeze your computer. Are you sure?")
d.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
d.setDefaultButton(QtGui.QMessageBox.Cancel)
@@ -12655,247 +13623,241 @@ def make_gr_arc_obj (a,pa):
stop
if 1:
dont_use_constraints = True
- FreeCAD.ActiveDocument.PCB_Sketch_draft.Geometry=PCB_Geo
+ FreeCAD.ActiveDocument.PCB_Sketch_draft.Geometry = PCB_Geo
else:
make_face = False
create_pcb_basic = True
else:
- #say (PCB_Geo)
- #for g in PCB_Geo:
+ # say (PCB_Geo)
+ # for g in PCB_Geo:
# FreeCAD.ActiveDocument.PCB_Sketch_draft.addGeometry(g)
- FreeCAD.ActiveDocument.PCB_Sketch_draft.Geometry=PCB_Geo
- #get_time()
- #say('adding Geo time ' +str(running_time-t0))
- #FreeCAD.ActiveDocument.addObject("Part::Face", "Face").Sources = (FreeCAD.ActiveDocument.getObject(new_skt.Name), )
-
- #FreeCADGui.SendMsgToActiveView("ViewFit")
- #stop
- HoleList=[]
- if lyr == 'Edge.Cuts':
- TopPadList=[]
- BotPadList=[]
- HoleList=[]
- THPList=[]
+ FreeCAD.ActiveDocument.PCB_Sketch_draft.Geometry = PCB_Geo
+ # get_time()
+ # say('adding Geo time ' +str(running_time-t0))
+ # FreeCAD.ActiveDocument.addObject("Part::Face", "Face").Sources = (FreeCAD.ActiveDocument.getObject(new_skt.Name), )
+
+ # FreeCADGui.SendMsgToActiveView("ViewFit")
+ # stop
+ HoleList = []
+ if lyr == "Edge.Cuts":
+ HoleList = []
## NB use always float() to guarantee number not string!!!
- warn=""
+ warn = ""
PCB_Models = []
- for m in mypcb.module: #parsing modules/footprints #check top/bottom for placing 3D models
- #print(m.tstamp);print(m.fp_text[0][1])
- #stop
+ for m in mypcb.module: # parsing modules/footprints #check top/bottom for placing 3D models
+ # print(m.tstamp);print(m.fp_text[0][1])
+ # stop
- if len(m.at)==2:
- m_angle=0
- else:
- m_angle=m.at[2]
- m_at=[m.at[0],-m.at[1]] #y reversed
- #say(m.layer);stop
- #HoleList = getPads(board_elab,pcbThickness)
+ m_angle = 0 if len(m.at) == 2 else m.at[2]
+ [m.at[0], -m.at[1]] # y reversed
+ # say(m.layer);stop
+ # HoleList = getPads(board_elab,pcbThickness)
# pad
- virtual=0
+ virtual = 0
dnp = False
# say(str(pcbv))
if pcbv <= 5:
Ref = get_mod_Ref(m)
- #print("Ref",Ref)
- if hasattr(m, 'attr'):
- if 'virtual' in m.attr:
- #say('virtual module')
- virtual=1
+ # print("Ref",Ref)
+ if hasattr(m, "attr"):
+ if "virtual" in m.attr:
+ # say('virtual module')
+ virtual = 1
else:
- virtual=0
- if get_mod_dnp(m,Ref):
- #print(Ref, 'has DNP or DNF option as field!')
- dnp=True
+ virtual = 0
+ if get_mod_dnp(m, Ref):
+ # print(Ref, 'has DNP or DNF option as field!')
+ dnp = True
elif pcbv > 5:
Ref = get_mod_Ref(m)
- #print("Ref",Ref)
- if hasattr(m, 'attr'):
- if 'virtual' in m.attr:
- #say('virtual module')
- virtual=1
- if 'dnp' in str(m.attr).lower():
- #print(Ref, 'has DNP or DNF option as attribute!')
- dnp=True
- if get_mod_dnp(m,Ref):
- #print(Ref, 'has DNP or DNF option as field!')
- dnp=True
- if 'smd' not in str(m.attr) and 'through_hole' not in str(m.attr):
+ # print("Ref",Ref)
+ if hasattr(m, "attr"):
+ if "virtual" in m.attr:
+ # say('virtual module')
+ virtual = 1
+ if "dnp" in str(m.attr).lower():
+ # print(Ref, 'has DNP or DNF option as attribute!')
+ dnp = True
+ if get_mod_dnp(m, Ref):
+ # print(Ref, 'has DNP or DNF option as field!')
+ dnp = True
+ if "smd" not in str(m.attr) and "through_hole" not in str(m.attr):
# 'exclude_from_pos_files' or 'exclude_from_bom'
# say('virtual module k>5')
- virtual=1
+ virtual = 1
else:
- #say('non virtual module')
- virtual=0
- else: # missing attribute (old 'virtual') -> 'other'
- #say('virtual module')
- virtual=1
+ # say('non virtual module')
+ virtual = 0
+ else: # missing attribute (old 'virtual') -> 'other'
+ # say('virtual module')
+ virtual = 1
m_x = float(m.at[0])
m_y = float(m.at[1]) * (-1)
m_rot = float(m_angle)
-
- #sayw(m.layer);sayerr(LvlTopName)
+
+ # sayw(m.layer);sayerr(LvlTopName)
if m.layer == LvlTopName: # top
side = "Top"
- #sayw('top ' + m.layer)
+ # sayw('top ' + m.layer)
else:
side = "Bottom"
- m_rot *= -1 ##bottom 3d model rotation
- #sayw('bot ' + m.layer)
-
- n_md=1
- for md in m.model: #parsing 3d model(s)
- #say (md[0]) #model name
- #say(md.at.xyz)
- #say(md.scale.xyz)
- #say(md.rotate.xyz)
- error_scale_module=False
- #say('scale ');sayw(scale_vrml)#;
- #error_scale_module=False
- xsc_vrml_val=md.scale.xyz[0]
- ysc_vrml_val=md.scale.xyz[1]
- zsc_vrml_val=md.scale.xyz[2]
+ m_rot *= -1 ##bottom 3d model rotation
+ # sayw('bot ' + m.layer)
+
+ n_md = 1
+ for md in m.model: # parsing 3d model(s)
+ # say (md[0]) #model name
+ # say(md.at.xyz)
+ # say(md.scale.xyz)
+ # say(md.rotate.xyz)
+ error_scale_module = False
+ # say('scale ');sayw(scale_vrml)#;
+ # error_scale_module=False
+ xsc_vrml_val = md.scale.xyz[0]
+ ysc_vrml_val = md.scale.xyz[1]
+ zsc_vrml_val = md.scale.xyz[2]
# if scale_vrml!='1 1 1':
- if float(xsc_vrml_val)!=1 or float(ysc_vrml_val)!=1 or float(zsc_vrml_val)!=1:
+ if float(xsc_vrml_val) != 1 or float(ysc_vrml_val) != 1 or float(zsc_vrml_val) != 1:
if "box_mcad" not in md[0] and "cylV_mcad" not in md[0] and "cylH_mcad" not in md[0]:
- sayw('wrong scale!!! set scale to (1 1 1)')
- error_scale_module=True
- #model_list.append(mdl_name[0])
- #model=model_list[j]+'.wrl'
- #if py2:
- if sys.version_info[0] == 2: #py2
- model=md[0].decode("utf-8")
- #stop
- else: #py3
- model=md[0] # py3 .decode("utf-8")
- #print (model, ' MODEL', type(model)) #maui test py3
+ sayw("wrong scale!!! set scale to (1 1 1)")
+ error_scale_module = True
+ # model_list.append(mdl_name[0])
+ # model=model_list[j]+'.wrl'
+ # if py2:
+ model = md[0] # py3 .decode("utf-8")
+ # print (model, ' MODEL', type(model)) #maui test py3
md_hide = False
# print('md value',md, len(md))
- #hide attribute on 3d model kv6+
+ # hide attribute on 3d model kv6+
try:
- if len(md) >4: #hide attribute on 3d model
- if md[1] == 'hide':
+ if len(md) > 4: # hide attribute on 3d model
+ if md[1] == "hide":
md_hide = True
- #print(md[0],'hidden')
+ # print(md[0],'hidden')
except:
- sayerr ('hide attribute on 3d model missing')
- pass
- if (virtual==1 and addVirtual==0):
- model_name='no3Dmodel'
- side='noLayer'
+ sayerr("hide attribute on 3d model missing")
+ if virtual == 1 and addVirtual == 0:
+ model_name = "no3Dmodel"
+ side = "noLayer"
if model:
- sayw("virtual model "+model+" skipped") #virtual found warning
- if (dnp and bklist_dnp):
- model_name='no3Dmodel'
- side='noLayer'
+ sayw("virtual model " + model + " skipped") # virtual found warning
+ if dnp and bklist_dnp:
+ model_name = "no3Dmodel"
+ side = "noLayer"
if model:
- sayw("Reference "+Ref+" skipped for DNP") #DNP found warning
- blacklisted_model_elements+=Ref+';'
+ sayw("Reference " + Ref + " skipped for DNP") # DNP found warning
+ blacklisted_model_elements += Ref + ";"
else:
if model:
- model_name=model
- #sayw(model_name)
- warn=""
- if "box_mcad" not in model_name and "cylV_mcad" not in model_name and "cylH_mcad" not in model_name:
- if error_scale_module:
- sayw('wrong scale!!! for '+model_name+' Set scale to (1 1 1)')
- msg="""Error in '.kicad_pcb' model footprint
"""
- msg+="
reset values of
"+model_name+"
to:
"
- msg+="(scale (xyz 1 1 1))
"
- #warn+=("reset values of scale to (xyz 1 1 1)")
- warn=("reset values of scale to (xyz 1 1 1)")
- ##reply = QtGui.QMessageBox.information(None,"info", msg)
- #stop
- #model_name=model_name[1:]
- #say(model_name)
- #sayw("here")
+ model_name = model
+ # sayw(model_name)
+ warn = ""
+ if (
+ "box_mcad" not in model_name
+ and "cylV_mcad" not in model_name
+ and "cylH_mcad" not in model_name
+ ) and error_scale_module:
+ sayw("wrong scale!!! for " + model_name + " Set scale to (1 1 1)")
+ msg = """Error in '.kicad_pcb' model footprint
"""
+ msg += "
reset values of
" + model_name + "
to:
"
+ msg += "(scale (xyz 1 1 1))
"
+ # warn+=("reset values of scale to (xyz 1 1 1)")
+ warn = "reset values of scale to (xyz 1 1 1)"
+ ##reply = QtGui.QMessageBox.information(None,"info", msg)
+ # stop
+ # model_name=model_name[1:]
+ # say(model_name)
+ # sayw("here")
else:
- model_name='no3Dmodel' #to do how to manage no3Dmodel
- side='noLayer'
- sayerr('no3Dmodel')
- mdl_name=model_name # re.findall(r'(.+?)\.wrl',params)
- #if virtual == 1:
+ model_name = "no3Dmodel" # to do how to manage no3Dmodel
+ side = "noLayer"
+ sayerr("no3Dmodel")
+ mdl_name = model_name # re.findall(r'(.+?)\.wrl',params)
+ # if virtual == 1:
# sayerr("virtual model(s)");sayw(mdl_name)
# sayw(mdl_name)
# sayerr(params)
if len(mdl_name) > 0:
# model_name, rot_comb, warn, pos_vrml, rotz_vrml, scale_vrml = get3DParams(mdl_name,params, rot, virtual)
- #sayerr(md.at.xyz)
- if conv_offs != 1: #pcb version >= 20171114 (offset wrl in mm)
- if hasattr(md,'at'):
- ofs=[md.at.xyz[0]/conv_offs,md.at.xyz[1]/conv_offs,md.at.xyz[2]/conv_offs]
- if hasattr(md,'offset'):
- ofs=[md.offset.xyz[0]/conv_offs,md.offset.xyz[1]/conv_offs,md.offset.xyz[2]/conv_offs]
+ # sayerr(md.at.xyz)
+ if conv_offs != 1: # pcb version >= 20171114 (offset wrl in mm)
+ if hasattr(md, "at"):
+ ofs = [md.at.xyz[0] / conv_offs, md.at.xyz[1] / conv_offs, md.at.xyz[2] / conv_offs]
+ if hasattr(md, "offset"):
+ ofs = [
+ md.offset.xyz[0] / conv_offs,
+ md.offset.xyz[1] / conv_offs,
+ md.offset.xyz[2] / conv_offs,
+ ]
else:
- ofs=md.at.xyz
+ ofs = md.at.xyz
line = []
line.append(model_name)
line.append(m_x)
line.append(m_y)
- line.append(m_rot-md.rotate.xyz[2])
+ line.append(m_rot - md.rotate.xyz[2])
line.append(side)
line.append(warn)
- line.append(ofs) #(md.at.xyz) #pos_vrml)
- line.append(md.rotate.xyz) #rotz_vrml)
- #sayerr(rotz_vrml)
- line.append(md.scale.xyz) #scale_vrml)
+ line.append(ofs) # (md.at.xyz) #pos_vrml)
+ line.append(md.rotate.xyz) # rotz_vrml)
+ # sayerr(rotz_vrml)
+ line.append(md.scale.xyz) # scale_vrml)
line.append(virtual)
- if hasattr(m,'tstamp'):
- line.append(m.tstamp) # fp tstamp
- elif hasattr(m,'uuid'):
- line.append(m.uuid) # fp tstamp
+ if hasattr(m, "tstamp"):
+ line.append(m.tstamp) # fp tstamp
+ elif hasattr(m, "uuid"):
+ line.append(m.uuid) # fp tstamp
else:
- sayw('missing \'TimeStamp\'')
- line.append('null')
- line.append(get_mod_Ref(m)) #fp reference kv8
+ sayw("missing 'TimeStamp'")
+ line.append("null")
+ line.append(get_mod_Ref(m)) # fp reference kv8
# try: # trying the kv8 property Reference
# #print(m.property[0])
# line.append(m.property[0][1]) #fp reference kv8
# except: # using the old kv5-kv7 method
# #print(m.fp_text[0])
# line.append(m.fp_text[0][1]) #fp reference
- line.append(n_md) #number of models in module
+ line.append(n_md) # number of models in module
line.append(md_hide)
PCB_Models.append(line)
- n_md+=1
-
- pads = []
+ n_md += 1
+
for p in m.pad:
- if 'drill' not in p:
- continue
- #say('drill present')
- #say (p.at)
- if len(p.at)>2:
- #say ('angle '+str(p.at[2]))
- p_angle=p.at[2]
+ if "drill" not in p:
+ continue
+ # say('drill present')
+ # say (p.at)
+ if len(p.at) > 2:
+ # say ('angle '+str(p.at[2]))
+ p_angle = p.at[2]
else:
- p_angle=0.0
- #say('drill');say(p.drill)
- #say('drill size');
- if hasattr(p,'drill'):
- if 'offset' in p.drill:
- #say('offset');say(p.drill.offset)
- offset=p.drill.offset
+ p_angle = 0.0
+ # say('drill');say(p.drill)
+ # say('drill size');
+ if hasattr(p, "drill"):
+ if "offset" in p.drill:
+ # say('offset');say(p.drill.offset)
+ pass
else:
- offset=[0,0]
+ pass
else:
- sayw('drill size missing');
- #say('offset not present')
- offset=[0,0]
- #print p.drill.oval
- #if p.drill.oval:
+ sayw("drill size missing")
+ # say('offset not present')
+ # print p.drill.oval
+ # if p.drill.oval:
# if p.drill[0] < min_drill_size and p.drill[1] < min_drill_size:
- # continue
- #else:
+ # continue
+ # else:
# if p.drill[0] < min_drill_size:
# continue
- #say ( p)
- #if 'circle' in p[2]:
+ # say ( p)
+ # if 'circle' in p[2]:
## NB use always float() to guarantee number not string!!!
- if hasattr(p,'drill'):
- #sayerr(p.drill);
- #sayw(p.drill.oval)
- #if p.drill.oval is not None
- #if len(p.drill)>1:
+ if hasattr(p, "drill"):
+ # sayerr(p.drill);
+ # sayw(p.drill.oval)
+ # if p.drill.oval is not None
+ # if len(p.drill)>1:
# if p.drill[1] == 'oval':
# drill_oval=True
# drill_oval=False
@@ -12906,77 +13868,94 @@ def make_gr_arc_obj (a,pa):
# drill_oval=True
# myidx+=1
# if drill_oval:
- #print (p.drill);print(p.drill.oval);print(str(p.drill).split(',')[0])
- #if p.drill.oval is not None:
- if 'oval' in str(p.drill).split(',')[0]: #py3 dict workaround
- #if p.drill.oval: #maui temp workaround errorchecking
- #sayw(str(p.drill.oval))
- #sayw('drill oval')
+ # print (p.drill);print(p.drill.oval);print(str(p.drill).split(',')[0])
+ # if p.drill.oval is not None:
+ if "oval" in str(p.drill).split(",")[0]: # py3 dict workaround
+ # if p.drill.oval: #maui temp workaround errorchecking
+ # sayw(str(p.drill.oval))
+ # sayw('drill oval')
# print (str(p.drill).split(','))
try:
if p.drill[0] >= min_drill_size or p.drill[1] >= min_drill_size:
- xs=p.at[0]+m.at[0];ys=-p.at[1]-m.at[1]
- #x1=mc.end[0]+m.at[0];y1=-mc.end[1]-m.at[1]
- #radius = float(p.drill[0])/2 #sqrt((xs - x1) ** 2 + (ys - y1) ** 2)
- rx=float(p.drill[0])
- #print (p.drill)
- if len(p.drill)>2:
+ xs = p.at[0] + m.at[0]
+ ys = -p.at[1] - m.at[1]
+ # x1=mc.end[0]+m.at[0];y1=-mc.end[1]-m.at[1]
+ # radius = float(p.drill[0])/2 #sqrt((xs - x1) ** 2 + (ys - y1) ** 2)
+ rx = float(p.drill[0])
+ # print (p.drill)
+ if len(p.drill) > 2:
try:
- #print (p.drill[1])
- #stop
- ry=float(p.drill[1])
+ # print (p.drill[1])
+ # stop
+ ry = float(p.drill[1])
except:
- ry=rx
+ ry = rx
else:
- ry=rx
- #print(p.at[0],p.at[1], p.drill[0])
+ ry = rx
+ # print(p.at[0],p.at[1], p.drill[0])
[x1, y1] = rotPoint2([xs, ys], [m.at[0], -m.at[1]], m_angle)
- #sayw('holes solid '+str(holes_solid))
+ # sayw('holes solid '+str(holes_solid))
if holes_solid:
- obj=createHole3(x1,y1,rx,ry,"oval",totalHeight) #need to be separated instructions
+ obj = createHole3(
+ x1,
+ y1,
+ rx,
+ ry,
+ "oval",
+ totalHeight,
+ ) # need to be separated instructions
else:
- obj=createHole4(x1,y1,rx,ry,"oval") #need to be separated instructions
- if p_angle!=0:
+ obj = createHole4(x1, y1, rx, ry, "oval") # need to be separated instructions
+ if p_angle != 0:
rotateObj(obj, [x1, y1, p_angle])
HoleList.append(obj)
except:
try:
- sayw('missing drill value on pad for module '+str(m.fp_text[0][1]))
+ sayw("missing drill value on pad for module " + str(m.fp_text[0][1]))
except:
- sayw('missing drill value on pad for module '+str(m.property[0][1]))
- #elif p.drill[0]!=0: #circle drill hole
+ sayw("missing drill value on pad for module " + str(m.property[0][1]))
+ # elif p.drill[0]!=0: #circle drill hole
else:
- try: # [0] >= min_drill_size: #isinstance(p.drill,list):
+ try: # [0] >= min_drill_size: #isinstance(p.drill,list):
# for t in m.fp_text:
# print(t[1])
if p.drill[0] >= min_drill_size:
- #xs=p.at[0]+offset[0]+m.at[0];ys=-p.at[1]-offset[1]-m.at[1]
- xs=p.at[0]+m.at[0];ys=-p.at[1]-m.at[1]
- #x1=mc.end[0]+m.at[0];y1=-mc.end[1]-m.at[1]
- radius = float(p.drill[0])#/2 #sqrt((xs - x1) ** 2 + (ys - y1) ** 2)
- rx=radius;ry=radius
- #print(p.at[0],p.at[1], p.drill[0])
+ # xs=p.at[0]+offset[0]+m.at[0];ys=-p.at[1]-offset[1]-m.at[1]
+ xs = p.at[0] + m.at[0]
+ ys = -p.at[1] - m.at[1]
+ # x1=mc.end[0]+m.at[0];y1=-mc.end[1]-m.at[1]
+ radius = float(p.drill[0]) # /2 #sqrt((xs - x1) ** 2 + (ys - y1) ** 2)
+ rx = radius
+ ry = radius
+ # print(p.at[0],p.at[1], p.drill[0])
[x1, y1] = rotPoint2([xs, ys], [m.at[0], -m.at[1]], m_angle)
if holes_solid:
- obj=createHole3(x1,y1,rx,ry,"oval",totalHeight) #need to be separated instructions
+ obj = createHole3(
+ x1,
+ y1,
+ rx,
+ ry,
+ "oval",
+ totalHeight,
+ ) # need to be separated instructions
else:
- obj=createHole4(x1,y1,rx,ry,"oval") #need to be separated instructions
- #say(HoleList)
- #if p_angle!=0:
+ obj = createHole4(x1, y1, rx, ry, "oval") # need to be separated instructions
+ # say(HoleList)
+ # if p_angle!=0:
# rotateObj(obj, [x1, y1, p_angle])
- #rotateObj(obj, [m.at[0], m.at[1], m_angle])
- HoleList.append(obj)
+ # rotateObj(obj, [m.at[0], m.at[1], m_angle])
+ HoleList.append(obj)
except:
try:
- sayw('missing drill value on pad for module '+str(m.fp_text[0][1]))
+ sayw("missing drill value on pad for module " + str(m.fp_text[0][1]))
except:
- sayw('missing drill value on pad for module '+str(m.property[0][1]))
- ##pads.append({'x': x, 'y': y, 'rot': rot, 'padType': pType, 'padShape': pShape, 'rx': drill_x, 'ry': drill_y, 'dx': dx, 'dy': dy, 'holeType': hType, 'xOF': xOF, 'yOF': yOF, 'layers': layers})
- #stop
- if hasattr(m, 'fp_poly'):
+ sayw("missing drill value on pad for module " + str(m.property[0][1]))
+ ##pads.append({'x': x, 'y': y, 'rot': rot, 'padType': pType, 'padShape': pShape, 'rx': drill_x, 'ry': drill_y, 'dx': dx, 'dy': dy, 'holeType': hType, 'xOF': xOF, 'yOF': yOF, 'layers': layers})
+ # stop
+ if hasattr(m, "fp_poly"):
for lp in m.fp_poly:
- #print(lp.layer)
- if 'Edge.Cuts' not in lp.layer:
+ # print(lp.layer)
+ if "Edge.Cuts" not in lp.layer:
continue
# print(m.layer)
# if m.layer != 'Edge.Cuts':
@@ -12985,136 +13964,176 @@ def make_gr_arc_obj (a,pa):
# print(lp.pts.xy)
# for p in lp.pts.xy:
# print(p)
- #if lp.layer != 'F.Cu':
- if 'F.Cu' not in m.layer:
+ # if lp.layer != 'F.Cu':
+ if "F.Cu" not in m.layer:
continue
- #print ml.start,ml.end
+ # print ml.start,ml.end
ind = 0
l = len(lp.pts.xy)
- #print(lp)
+ # print(lp)
for p in lp.pts.xy:
- #print('p',p)
+ # print('p',p)
if ind == 0:
- line1=Part.Edge(PLine(Base.Vector(lp.pts.xy[l-1][0],-lp.pts.xy[l-1][1],0), Base.Vector(lp.pts.xy[0][0],-lp.pts.xy[0][1],0)))
- edges.append(line1);
+ line1 = Part.Edge(
+ PLine(
+ Base.Vector(lp.pts.xy[l - 1][0], -lp.pts.xy[l - 1][1], 0),
+ Base.Vector(lp.pts.xy[0][0], -lp.pts.xy[0][1], 0),
+ ),
+ )
+ edges.append(line1)
else:
- line1=Part.Edge(PLine(Base.Vector(lp.pts.xy[ind-1][0],-lp.pts.xy[ind-1][1],0), Base.Vector(lp.pts.xy[ind][0],-lp.pts.xy[ind][1],0)))
- edges.append(line1);
- ind+=1
+ line1 = Part.Edge(
+ PLine(
+ Base.Vector(lp.pts.xy[ind - 1][0], -lp.pts.xy[ind - 1][1], 0),
+ Base.Vector(lp.pts.xy[ind][0], -lp.pts.xy[ind][1], 0),
+ ),
+ )
+ edges.append(line1)
+ ind += 1
EdgeCuts.append(line1)
- #print(line1.Vertexes[0].Point.x,line1.Vertexes[0].Point.y)
- #line1.Vertexes[1].Point)
- pt1 = (line1.Vertexes[0].Point.x,-line1.Vertexes[0].Point.y)
- pt2 = (line1.Vertexes[1].Point.x,-line1.Vertexes[1].Point.y)
- x1=pt1[0]+m.at[0];y1=-pt1[1]-m.at[1]
- x2=pt2[0]+m.at[0];y2=-pt2[1]-m.at[1]
- [x1, y1] = rotPoint2([x1,y1], [m.at[0], -m.at[1]], m_angle)
- [x2, y2] = rotPoint2([x2,y2], [m.at[0], -m.at[1]], m_angle)
- if aux_orig ==1 or grid_orig ==1:
- FpEdges_Geo.append(PLine(Base.Vector(x1-off_x,y1-off_y,0), Base.Vector(x2-off_x,y2-off_y,0)))
+ # print(line1.Vertexes[0].Point.x,line1.Vertexes[0].Point.y)
+ # line1.Vertexes[1].Point)
+ pt1 = (line1.Vertexes[0].Point.x, -line1.Vertexes[0].Point.y)
+ pt2 = (line1.Vertexes[1].Point.x, -line1.Vertexes[1].Point.y)
+ x1 = pt1[0] + m.at[0]
+ y1 = -pt1[1] - m.at[1]
+ x2 = pt2[0] + m.at[0]
+ y2 = -pt2[1] - m.at[1]
+ [x1, y1] = rotPoint2([x1, y1], [m.at[0], -m.at[1]], m_angle)
+ [x2, y2] = rotPoint2([x2, y2], [m.at[0], -m.at[1]], m_angle)
+ if aux_orig == 1 or grid_orig == 1:
+ FpEdges_Geo.append(
+ PLine(Base.Vector(x1 - off_x, y1 - off_y, 0), Base.Vector(x2 - off_x, y2 - off_y, 0)),
+ )
else:
- FpEdges_Geo.append(PLine(Base.Vector(x1,y1,0), Base.Vector(x2,y2,0)))
- PCB.append(['Line', x1, y1, x2, y2])
- #closing edge
- if show_border: #0: #SHOW POLY BORDER
+ FpEdges_Geo.append(PLine(Base.Vector(x1, y1, 0), Base.Vector(x2, y2, 0)))
+ PCB.append(["Line", x1, y1, x2, y2])
+ # closing edge
+ if show_border: # 0: #SHOW POLY BORDER
Part.show(line1)
- #stop
+ # stop
if min_drill_size == -1:
for v in mypcb.via:
- # based on code above for pads
- if 'drill' not in v:
+ # based on code above for pads
+ if "drill" not in v:
continue
- if hasattr(v,'drill'):
- #if drill_present:
+ if hasattr(v, "drill"):
+ # if drill_present:
if v.drill >= min_drill_size:
- x1=v.at[0];y1=-v.at[1]
+ x1 = v.at[0]
+ y1 = -v.at[1]
radius = float(v.drill)
- rx=radius;ry=radius
+ rx = radius
+ ry = radius
if holes_solid:
- obj=createHole3(x1,y1,rx,ry,"oval",totalHeight) #need to be separated instructions
+ obj = createHole3(
+ x1,
+ y1,
+ rx,
+ ry,
+ "oval",
+ totalHeight,
+ ) # need to be separated instructions
else:
- obj=createHole4(x1,y1,rx,ry,"oval") #need to be separated instructions
+ obj = createHole4(x1, y1, rx, ry, "oval") # need to be separated instructions
HoleList.append(obj)
else:
- sayw('drill size missing');
-
+ sayw("drill size missing")
+
for ml in m.fp_line:
# if ml.layer != 'Edge.Cuts':
if lyr not in ml.layer:
continue
- #print ml.start,ml.end
- x1=ml.start[0]+m.at[0];y1=-ml.start[1]-m.at[1]
- x2=ml.end[0]+m.at[0];y2=-ml.end[1]-m.at[1]
- [x1, y1] = rotPoint2([x1,y1], [m.at[0], -m.at[1]], m_angle)
- [x2, y2] = rotPoint2([x2,y2], [m.at[0], -m.at[1]], m_angle)
- if (Base.Vector(x1,y1,0)) != (Base.Vector(x2,y2,0)): #non coincident points
- line1=Part.Edge(PLine(Base.Vector(x1,y1,0), Base.Vector(x2,y2,0)))
- edges.append(line1);
+ # print ml.start,ml.end
+ x1 = ml.start[0] + m.at[0]
+ y1 = -ml.start[1] - m.at[1]
+ x2 = ml.end[0] + m.at[0]
+ y2 = -ml.end[1] - m.at[1]
+ [x1, y1] = rotPoint2([x1, y1], [m.at[0], -m.at[1]], m_angle)
+ [x2, y2] = rotPoint2([x2, y2], [m.at[0], -m.at[1]], m_angle)
+ if (Base.Vector(x1, y1, 0)) != (Base.Vector(x2, y2, 0)): # non coincident points
+ line1 = Part.Edge(PLine(Base.Vector(x1, y1, 0), Base.Vector(x2, y2, 0)))
+ edges.append(line1)
EdgeCuts.append(line1)
- if aux_orig ==1 or grid_orig ==1:
- FpEdges_Geo.append(PLine(Base.Vector(x1-off_x,y1-off_y,0), Base.Vector(x2-off_x,y2-off_y,0)))
+ if aux_orig == 1 or grid_orig == 1:
+ FpEdges_Geo.append(
+ PLine(Base.Vector(x1 - off_x, y1 - off_y, 0), Base.Vector(x2 - off_x, y2 - off_y, 0)),
+ )
else:
- FpEdges_Geo.append(PLine(Base.Vector(x1,y1,0), Base.Vector(x2,y2,0)))
- PCB.append(['Line', x1, y1, x2, y2])
+ FpEdges_Geo.append(PLine(Base.Vector(x1, y1, 0), Base.Vector(x2, y2, 0)))
+ PCB.append(["Line", x1, y1, x2, y2])
if show_border:
Part.show(line1)
for mc in m.fp_circle:
# if mc.layer != 'Edge.Cuts':
if lyr not in mc.layer:
continue
- xs=mc.center[0]+m.at[0];ys=-mc.center[1]-m.at[1]
- x1=mc.end[0]+m.at[0];y1=-mc.end[1]-m.at[1]
+ xs = mc.center[0] + m.at[0]
+ ys = -mc.center[1] - m.at[1]
+ x1 = mc.end[0] + m.at[0]
+ y1 = -mc.end[1] - m.at[1]
radius = sqrt((xs - x1) ** 2 + (ys - y1) ** 2)
[xc, yc] = rotPoint2([xs, ys], [m.at[0], -m.at[1]], m_angle)
- circle1=Part.Edge(Part.Circle(Base.Vector(xc, yc,0), Base.Vector(0, 0, 1), radius))
+ circle1 = Part.Edge(Part.Circle(Base.Vector(xc, yc, 0), Base.Vector(0, 0, 1), radius))
# print (mc.center,mc.end)
# print (xs,ys)
# print(radius)
- circle2=circle1
+ circle2 = circle1
if show_border:
Part.show(circle1)
- circle1=Part.Wire(circle1)
- circle1=Part.Face(circle1)
+ circle1 = Part.Wire(circle1)
+ circle1 = Part.Face(circle1)
if show_shapes:
Part.show(circle1)
- say('2d circle closed path')
+ say("2d circle closed path")
PCBs.append(circle1)
EdgeCuts.append(circle2)
- if aux_orig ==1 or grid_orig ==1:
- FpEdges_Geo.append(Part.Circle(Base.Vector(xc-off_x, yc-off_y,0), Base.Vector(0, 0, 1), radius))
+ if aux_orig == 1 or grid_orig == 1:
+ FpEdges_Geo.append(
+ Part.Circle(Base.Vector(xc - off_x, yc - off_y, 0), Base.Vector(0, 0, 1), radius),
+ )
else:
- FpEdges_Geo.append(Part.Circle(Base.Vector(xc, yc,0), Base.Vector(0, 0, 1), radius))
- PCB.append(['Circle', x1, y1, radius])
- #mod_circles.append (['Circle', x1, y1, e[2]])
- #PCB.append(['Circle', x1, y1, radius])
+ FpEdges_Geo.append(Part.Circle(Base.Vector(xc, yc, 0), Base.Vector(0, 0, 1), radius))
+ PCB.append(["Circle", x1, y1, radius])
+ # mod_circles.append (['Circle', x1, y1, e[2]])
+ # PCB.append(['Circle', x1, y1, radius])
for ma in m.fp_arc:
# if ma.layer != 'Edge.Cuts':
if lyr not in ma.layer:
continue
- #print ma.start, ma.end, ma.angle
- #xs=ma.start[0]+m.at[0];ys=-ma.start[1]-m.at[1]
- #x1=ma.end[0]+m.at[0];y1=-ma.end[1]-m.at[1]
- xs=ma.start[0];ys=ma.start[1]
- x1=ma.end[0];y1=ma.end[1]
- if hasattr (ma, 'mid'):
- [xm, ym] = ma.mid
- #arc2 = Part.Edge(Part.Arc(Base.Vector(xs,-ys,0),Base.Vector(xm,-ym,0),Base.Vector(x1,-y1,0)))
- arc1 = Part.Edge(Part.ArcOfCircle(kicad_parser.makeVect(ma.start), kicad_parser.makeVect(ma.mid), kicad_parser.makeVect(ma.end)).toShape())
- arc1.rotate(Vector(),Vector(0,0,1),m_angle)
- if aux_orig ==1 or grid_orig ==1:
- mat_t=(m.at[0]-off_x,-m.at[1]-off_y,0)
+ # print ma.start, ma.end, ma.angle
+ # xs=ma.start[0]+m.at[0];ys=-ma.start[1]-m.at[1]
+ # x1=ma.end[0]+m.at[0];y1=-ma.end[1]-m.at[1]
+ xs = ma.start[0]
+ ys = ma.start[1]
+ x1 = ma.end[0]
+ y1 = ma.end[1]
+ if hasattr(ma, "mid"):
+ [_xm, _ym] = ma.mid
+ # arc2 = Part.Edge(Part.Arc(Base.Vector(xs,-ys,0),Base.Vector(xm,-ym,0),Base.Vector(x1,-y1,0)))
+ arc1 = Part.Edge(
+ Part.ArcOfCircle(
+ kicad_parser.makeVect(ma.start),
+ kicad_parser.makeVect(ma.mid),
+ kicad_parser.makeVect(ma.end),
+ ).toShape(),
+ )
+ arc1.rotate(Vector(), Vector(0, 0, 1), m_angle)
+ if aux_orig == 1 or grid_orig == 1:
+ mat_t = (m.at[0] - off_x, -m.at[1] - off_y, 0)
else:
- mat_t=(m.at[0],-m.at[1],0)
+ mat_t = (m.at[0], -m.at[1], 0)
arc1.translate(mat_t)
edges.append(arc1)
EdgeCuts.append(arc1)
- delta_angle=degrees(arc1.LastParameter-arc1.FirstParameter)
+ delta_angle = degrees(arc1.LastParameter - arc1.FirstParameter)
curve = delta_angle
- [x2, y2] = [xs,ys] #rotPoint2([x1, y1], [xs, ys], curve)
- sa,ea = arcAngles2(arc1,curve)
+ [x2, y2] = [xs, ys] # rotPoint2([x1, y1], [xs, ys], curve)
+ sa, ea = arcAngles2(arc1, curve)
Cntr = arc1.Curve.Center
- cx=Cntr.x;cy=Cntr.y
- #print cx,cy
+ cx = Cntr.x
+ cy = Cntr.y
+ # print cx,cy
r = arc1.Curve.Radius
skt = Draft.makeSketch(arc1)
FpEdges_Geo.append(skt.Geometry[0])
@@ -13122,62 +14141,90 @@ def make_gr_arc_obj (a,pa):
else:
curve = ma.angle
[x2, y2] = rotPoint2([x1, y1], [xs, ys], curve)
- y1=-y1-m.at[1]; y2=-y2-m.at[1]
- x1+=m.at[0];x2+=m.at[0]
+ y1 = -y1 - m.at[1]
+ y2 = -y2 - m.at[1]
+ x1 += m.at[0]
+ x2 += m.at[0]
[x1, y1] = rotPoint2([x1, y1], [m.at[0], -m.at[1]], m_angle)
[x2, y2] = rotPoint2([x2, y2], [m.at[0], -m.at[1]], m_angle)
- arc1=Part.Edge(Part.Arc(Base.Vector(x2,y2,0),mid_point(Base.Vector(x2,y2,0),Base.Vector(x1,y1,0),curve),Base.Vector(x1,y1,0)))
+ arc1 = Part.Edge(
+ Part.Arc(
+ Base.Vector(x2, y2, 0),
+ mid_point(Base.Vector(x2, y2, 0), Base.Vector(x1, y1, 0), curve),
+ Base.Vector(x1, y1, 0),
+ ),
+ )
edges.append(arc1)
EdgeCuts.append(arc1)
- sa,ea = arcAngles2(arc1,curve)
+ sa, ea = arcAngles2(arc1, curve)
Cntr = arc1.Curve.Center
- cx=Cntr.x;cy=Cntr.y
- #print cx,cy
+ cx = Cntr.x
+ cy = Cntr.y
+ # print cx,cy
r = arc1.Curve.Radius
- if aux_orig ==1 or grid_orig ==1:
- FpEdges_Geo.append(Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx-off_x,cy-off_y,0),FreeCAD.Vector(0,0,1),r),sa,ea))
+ if aux_orig == 1 or grid_orig == 1:
+ FpEdges_Geo.append(
+ Part.ArcOfCircle(
+ Part.Circle(FreeCAD.Vector(cx - off_x, cy - off_y, 0), FreeCAD.Vector(0, 0, 1), r),
+ sa,
+ ea,
+ ),
+ )
else:
- FpEdges_Geo.append(Part.ArcOfCircle(Part.Circle(FreeCAD.Vector(cx,cy,0),FreeCAD.Vector(0,0,1),r),sa,ea))
+ FpEdges_Geo.append(
+ Part.ArcOfCircle(
+ Part.Circle(FreeCAD.Vector(cx, cy, 0), FreeCAD.Vector(0, 0, 1), r), sa, ea
+ ),
+ )
if show_border:
Part.show(arc1)
- PCB.append(['Arc', x1, y1, x2, y2, curve])
+ PCB.append(["Arc", x1, y1, x2, y2, curve])
- if 0: #this is not needed anymoore because we have built a PCB_Sketch_draft from Edges
- if len(EdgeCuts) >0 and not create_pcb_from_edges:
+ if 0: # this is not needed anymoore because we have built a PCB_Sketch_draft from Edges
+ if len(EdgeCuts) > 0 and not create_pcb_from_edges:
try:
- s_PCB_Cuts = OSCD2Dg_edgestofaces(EdgeCuts,3 , edge_tolerance)
+ s_PCB_Cuts = OSCD2Dg_edgestofaces(EdgeCuts, 3, edge_tolerance)
HoleList.append(s_PCB_Cuts)
except:
- sayerr('error in making footprint Edge Cuts')
+ sayerr("error in making footprint Edge Cuts")
elif len(EdgeCuts) > 0:
try:
- s_PCB_Cuts = OSCD2Dg_edgestofaces(EdgeCuts,3 , edge_tolerance)
- #Part.show(s_PCB_Cuts)
+ s_PCB_Cuts = OSCD2Dg_edgestofaces(EdgeCuts, 3, edge_tolerance)
+ # Part.show(s_PCB_Cuts)
except:
- sayerr('error in making PCB from footprint Edge Cuts')
- #creating a sketch with fp edges
+ sayerr("error in making PCB from footprint Edge Cuts")
+ # creating a sketch with fp edges
if len(EdgeCuts) > 0:
- PCB_Sketch_draft_E= FreeCAD.activeDocument().addObject('Sketcher::SketchObject','PCB_Sketch_draft_E')
- FreeCAD.activeDocument().PCB_Sketch_draft_E.Placement = FreeCAD.Placement(FreeCAD.Vector(0.000000,0.000000,0.000000),FreeCAD.Rotation(0.000000,0.000000,0.000000,1.000000))
- FreeCAD.ActiveDocument.PCB_Sketch_draft_E.Geometry=PCB_Geo+FpEdges_Geo
+ PCB_Sketch_draft_E = FreeCAD.activeDocument().addObject("Sketcher::SketchObject", "PCB_Sketch_draft_E")
+ FreeCAD.activeDocument().PCB_Sketch_draft_E.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0.000000, 0.000000, 0.000000),
+ FreeCAD.Rotation(0.000000, 0.000000, 0.000000, 1.000000),
+ )
+ FreeCAD.ActiveDocument.PCB_Sketch_draft_E.Geometry = PCB_Geo + FpEdges_Geo
use_PCB_Sketch_E = True
- if lyr == 'Edge.Cuts':
- if make_face: #creation pcb from PCB sketch draft
+ if lyr == "Edge.Cuts":
+ if make_face: # creation pcb from PCB sketch draft
if use_PCB_Sketch_E:
- PCB2Sketch=FreeCAD.ActiveDocument.PCB_Sketch_draft_E
+ PCB2Sketch = FreeCAD.ActiveDocument.PCB_Sketch_draft_E
else:
- PCB2Sketch=FreeCAD.ActiveDocument.PCB_Sketch_draft
- if len(PCB2Sketch.Geometry)>0:
- if addConstraints!='none' and not dont_use_constraints:
- say('start adding constraints to pcb sketch')
+ PCB2Sketch = FreeCAD.ActiveDocument.PCB_Sketch_draft
+ if len(PCB2Sketch.Geometry) > 0:
+ if addConstraints != "none" and not dont_use_constraints:
+ say("start adding constraints to pcb sketch")
get_time()
- t0=(running_time)
- if hasattr (FreeCAD.ActiveDocument.getObject(PCB2Sketch.Name), "autoconstraint"):
- if addConstraints=='full':
- FreeCAD.ActiveDocument.getObject("PCB_Sketch_draft").autoconstraint(edge_tolerance*5,0.01)
+ t0 = running_time
+ if hasattr(FreeCAD.ActiveDocument.getObject(PCB2Sketch.Name), "autoconstraint"):
+ if addConstraints == "full":
+ FreeCAD.ActiveDocument.getObject("PCB_Sketch_draft").autoconstraint(
+ edge_tolerance * 5,
+ 0.01,
+ )
if use_PCB_Sketch_E:
- FreeCAD.ActiveDocument.getObject("PCB_Sketch_draft_E").autoconstraint(edge_tolerance*5,0.01)
+ FreeCAD.ActiveDocument.getObject("PCB_Sketch_draft_E").autoconstraint(
+ edge_tolerance * 5,
+ 0.01,
+ )
else:
add_constraints("PCB_Sketch_draft")
if use_PCB_Sketch_E:
@@ -13187,48 +14234,51 @@ def make_gr_arc_obj (a,pa):
if use_PCB_Sketch_E:
add_constraints("PCB_Sketch_draft_E")
get_time()
- #say('adding constraints time ' +str(running_time-t0))
- say('adding constraints time ' + "{0:.3f}".format(running_time-t0))
- if 0: #dont_use_constraints:
- sayw('adding missing geometry')
+ # say('adding constraints time ' +str(running_time-t0))
+ say("adding constraints time " + f"{running_time - t0:.3f}")
+ if 0: # dont_use_constraints:
+ sayw("adding missing geometry")
add_missing_geo("PCB_Sketch_draft")
- #stop
-
+ # stop
+
make_face_mode = 1
FreeCAD.ActiveDocument.recompute()
if make_face_mode == 1: ## face creation method
shsk = PCB2Sketch.Shape.copy()
- #Part.show(shsk)
+ # Part.show(shsk)
edgs = shsk.Edges
- #print(edgs)
- if len(edgs)== 0:
- sayerr('No edges found for pcb!!!')
+ # print(edgs)
+ if len(edgs) == 0:
+ sayerr("No edges found for pcb!!!")
stop
if 1:
- s_PCB_Sketch_draft = OSCD2Dg_edgestofaces(edgs,3 , edge_tolerance)
+ s_PCB_Sketch_draft = OSCD2Dg_edgestofaces(edgs, 3, edge_tolerance)
if 0:
import OpenSCAD2Dgeom
+
s_PCB_Sketch_draft = OpenSCAD2Dgeom.edgestofaces(Part.__sortEdges__(edgs))
Part.show(s_PCB_Sketch_draft)
Face_PCB_Sketch_draft = FreeCAD.ActiveDocument.ActiveObject
s_PCB_Sketch_draft = Face_PCB_Sketch_draft.Shape.copy()
## OpenSCAD2Dgeom.edgestofaces(edgs)
-
+
else:
- FreeCAD.ActiveDocument.addObject("Part::Face", "Face_PCB_Sketch_draft").Sources = (PCB2Sketch, ) #(FreeCAD.ActiveDocument.PCB_Sketch_draft, )
+ FreeCAD.ActiveDocument.addObject("Part::Face", "Face_PCB_Sketch_draft").Sources = (
+ PCB2Sketch,
+ ) # (FreeCAD.ActiveDocument.PCB_Sketch_draft, )
FreeCAD.ActiveDocument.recompute()
s_PCB_Sketch_draft = FreeCAD.ActiveDocument.getObject("Face_PCB_Sketch_draft").Shape.copy()
-
- #s_PCB_Sketch_draft = s.copy()
- sayw ('created PCB face w/ edge tolerance -> '+str(edge_tolerance)+' mm')
- if aux_orig ==1 or grid_orig ==1:
- s_PCB_Sketch_draft.translate((off_x, off_y,0))
- #else:
+
+ # s_PCB_Sketch_draft = s.copy()
+ sayw("created PCB face w/ edge tolerance -> " + str(edge_tolerance) + " mm")
+ if aux_orig == 1 or grid_orig == 1:
+ s_PCB_Sketch_draft.translate((off_x, off_y, 0))
+ # else:
# s_PCB_Sketch_draft.translate(xs, ys,0)
- #if use_Links:
- #Part.show(s_PCB_Sketch_draft)
+ # if use_Links:
+ # Part.show(s_PCB_Sketch_draft)
if make_face_mode == 1: ## face creation method
- #if 0:
+ # if 0:
FreeCAD.ActiveDocument.removeObject(Face_PCB_Sketch_draft.Name)
if use_PCB_Sketch_E:
FreeCAD.ActiveDocument.removeObject(PCB_Sketch_draft_E.Name)
@@ -13238,228 +14288,250 @@ def make_gr_arc_obj (a,pa):
if use_PCB_Sketch_E:
FreeCAD.ActiveDocument.removeObject(PCB_Sketch_draft_E.Name)
FreeCAD.ActiveDocument.recompute()
-
- #FreeCAD.ActiveDocument.addObject("Part::Face", "Face").Sources = (FreeCAD.ActiveDocument.PCB_Sketch_draft001, )
- if (zfit):
+
+ # FreeCAD.ActiveDocument.addObject("Part::Face", "Face").Sources = (FreeCAD.ActiveDocument.PCB_Sketch_draft001, )
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
cut_base = s_PCB_Sketch_draft
else:
- sayerr('empty sketch; module edge board: creating PCB from Footprint Edge.Cuts')
+ sayerr("empty sketch; module edge board: creating PCB from Footprint Edge.Cuts")
create_pcb_from_edges = True
LCS = None
- #if aux_orig ==1 or grid_orig ==1:
- if origin is not None: #adding LCS only on aux or grid origin
+ # if aux_orig ==1 or grid_orig ==1:
+ if origin is not None: # adding LCS only on aux or grid origin
try:
- FreeCAD.ActiveDocument.addObject('PartDesign::CoordinateSystem','Local_CS'+fname_sfx)
+ FreeCAD.ActiveDocument.addObject("PartDesign::CoordinateSystem", "Local_CS" + fname_sfx)
LCS = FreeCAD.ActiveDocument.ActiveObject
FreeCADGui.ActiveDocument.getObject(LCS.Name).Visibility = False
FreeCADGui.Selection.clearSelection()
- #FreeCADGui.Selection.addSelection(LCS)
- #FreeCADGui.runCommand('Std_HideSelection',0)
- #FreeCADGui.runCommand('Std_ToggleVisibility',0)
- #FreeCADGui.Selection.clearSelection()
+ # FreeCADGui.Selection.addSelection(LCS)
+ # FreeCADGui.runCommand('Std_HideSelection',0)
+ # FreeCADGui.runCommand('Std_ToggleVisibility',0)
+ # FreeCADGui.Selection.clearSelection()
except:
- sayw('LCS not supported')
-
+ sayw("LCS not supported")
+
if 0:
Part.show(s_PCB_Cuts)
fc_PCB_Cuts = FreeCAD.ActiveDocument.ActiveObject
face_PCB_Cuts = fc_PCB_Cuts.Shape.copy()
- if aux_orig ==1 or grid_orig ==1:
- face_PCB_Cuts.translate((-off_x, -off_y,0))
+ if aux_orig == 1 or grid_orig == 1:
+ face_PCB_Cuts.translate((-off_x, -off_y, 0))
Part.show(face_PCB_Cuts)
- #obj = FreeCAD.ActiveDocument.ActiveObject
- #stop
- #HoleList.append(face_PCB_Cuts)
- #stop PCB_Cuts
- #sayw(len(HoleList))
- #say (PCB_Models)
- #stop
-
- #g = App.ActiveDocument.PCB_Sketch.Geometry
- #g = App.ActiveDocument.PCB_Sketch
+ # obj = FreeCAD.ActiveDocument.ActiveObject
+ # stop
+ # HoleList.append(face_PCB_Cuts)
+ # stop PCB_Cuts
+ # sayw(len(HoleList))
+ # say (PCB_Models)
+ # stop
+
+ # g = App.ActiveDocument.PCB_Sketch.Geometry
+ # g = App.ActiveDocument.PCB_Sketch
# For each sketch geometry type, map a list of points to move.
-
-
- # Direct access to sketch.Geometry[index] does not work. This would,
- # however prevent repeated recompute.
- #for point_index in point_indexes:
- # point = PCB_Sketch.getPoint(geom_index, point_index)
- # sayerr (point)
- # sayw(point[0]);sayw(point[1])
- # ## ckeck point coincidence for sketch constrains
- # #sketch.movePoint(geom_index, point_index, point)
- #
- #for i, pidx in enumerate(point_indexes):
- # for pidx2 in point_indexes[(i + 1):]:
- # point = PCB_Sketch.getPoint(geom_index, pidx)
- # point2 = PCB_Sketch.getPoint(geom_index, pidx2)
- # sayerr(pidx);sayw(pidx2)
- # sayerr('points')
- # sayw(point[0]);sayw(point[1]);sayw(point2[0]);sayw(point2[1])
- # if point[0] == point2[0]:
- # say('found 00')
- # PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',idx,1,idx2,1))
- # if point[1] == point2[0]:
- # say('found 10')
- # PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',idx,2,idx2,1))
- # if point[0] == point2[1]:
- # say('found 01')
- # PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',idx,1,idx2,2))
- # if point[1] == point2[1]:
- # say('found 11')
- # PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',idx,2,idx2,2))
- #
-
+
+ # Direct access to sketch.Geometry[index] does not work. This would,
+ # however prevent repeated recompute.
+ # for point_index in point_indexes:
+ # point = PCB_Sketch.getPoint(geom_index, point_index)
+ # sayerr (point)
+ # sayw(point[0]);sayw(point[1])
+ # ## ckeck point coincidence for sketch constrains
+ # #sketch.movePoint(geom_index, point_index, point)
+ #
+ # for i, pidx in enumerate(point_indexes):
+ # for pidx2 in point_indexes[(i + 1):]:
+ # point = PCB_Sketch.getPoint(geom_index, pidx)
+ # point2 = PCB_Sketch.getPoint(geom_index, pidx2)
+ # sayerr(pidx);sayw(pidx2)
+ # sayerr('points')
+ # sayw(point[0]);sayw(point[1]);sayw(point2[0]);sayw(point2[1])
+ # if point[0] == point2[0]:
+ # say('found 00')
+ # PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',idx,1,idx2,1))
+ # if point[1] == point2[0]:
+ # say('found 10')
+ # PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',idx,2,idx2,1))
+ # if point[0] == point2[1]:
+ # say('found 01')
+ # PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',idx,1,idx2,2))
+ # if point[1] == point2[1]:
+ # say('found 11')
+ # PCB_Sketch.addConstraint(Sketcher.Constraint('Coincident',idx,2,idx2,2))
+ #
+
FreeCAD.ActiveDocument.recompute()
-
- #add_constraints(PCB_Sketch_draft.Name)
- #t_name=cpy_sketch(PCB_Sketch_draft.Name)
+
+ # add_constraints(PCB_Sketch_draft.Name)
+ # t_name=cpy_sketch(PCB_Sketch_draft.Name)
##s_name=shift_sketch(PCB_Sketch_draft.Name, [-100,-100])
- ##add_constraints(s_name)
+ ##add_constraints(s_name)
##FreeCADGui.SendMsgToActiveView("ViewFit")
##stop
- #stop
- #Sketch.addConstraint(Sketcher.Constraint('Coincident',LineFixed,PointOfLineFixed,LineMoving,PointOfLineMoving))
-
- #for geom in PCB_Sketch.Geometry:
+ # stop
+ # Sketch.addConstraint(Sketcher.Constraint('Coincident',LineFixed,PointOfLineFixed,LineMoving,PointOfLineMoving))
+
+ # for geom in PCB_Sketch.Geometry:
# #if isinstance(geom, Part.Line):
# # bbox.enlarge_line(geom)
# if isinstance(geom, Part.Circle):
# say("Circle")
# elif isinstance(geom, Part.ArcOfCircle):
# say("Arc")
-
- #for i, e1 in enumerate(g):
+
+ # for i, e1 in enumerate(g):
# for e2 in g[(i + 1):]:
# sayw(e2.SubObjects[0].Curve)
-
- #sort edges to form a single closed 2D shape
+
+ # sort edges to form a single closed 2D shape
loopcounter = 0
- #sayw((edges))
- #stop
+ # sayw((edges))
+ # stop
# for f in PCBs:
# Part.show(f)
# stop
- if create_pcb_from_edges:
- #if not test_face:
- #sayerr('doing')
- if (len(edges)==0) and (len(PCBs)==0):
+ if create_pcb_from_edges:
+ # if not test_face:
+ # sayerr('doing')
+ if (len(edges) == 0) and (len(PCBs) == 0):
sayw("no PCBs found")
else:
- sayerr('creating pcb from edges instead of sketch')
- newEdges = [];
- if (len(edges)>0):
+ sayerr("creating pcb from edges instead of sketch")
+ newEdges = []
+ if len(edges) > 0:
newEdges.append(edges.pop(0))
- #say(newEdges[0])
- #print [newEdges[0].Vertexes[0].Point]
- #print [newEdges[0].Vertexes[-1].Point]
- #say(str(len(newEdges[0].Vertexes)))
+ # say(newEdges[0])
+ # print [newEdges[0].Vertexes[0].Point]
+ # print [newEdges[0].Vertexes[-1].Point]
+ # say(str(len(newEdges[0].Vertexes)))
nextCoordinate = newEdges[0].Vertexes[0].Point
firstCoordinate = newEdges[0].Vertexes[-1].Point
- #nextCoordinate = newEdges[0].Curve.EndPoint
- #firstCoordinate = newEdges[0].Curve.StartPoint
+ # nextCoordinate = newEdges[0].Curve.EndPoint
+ # firstCoordinate = newEdges[0].Curve.StartPoint
if apply_edge_tolerance:
for e in edges:
- for v in e.Vertexes: v.setTolerance(edge_tolerance) #adding tolerance to vertex
+ for v in e.Vertexes:
+ v.setTolerance(edge_tolerance) # adding tolerance to vertex
if show_data:
# print findWires(edges)
sayw(len(edges))
for e in edges:
- sayw(e.Vertexes[0].Point);sayw(e.Vertexes[-1].Point)
+ sayw(e.Vertexes[0].Point)
+ sayw(e.Vertexes[-1].Point)
for e in edges:
sayw("geomType")
- say(DraftGeomUtils.geomType(e))
- #if show_data:
+ say(DraftGeomUtils.geomType(e))
+ # if show_data:
# sayw(enumerate(edges));
- while(len(edges)>0 and loopcounter < 2):
+ while len(edges) > 0 and loopcounter < 2:
loopcounter = loopcounter + 1
- #print "nextCoordinate: ", nextCoordinate
- #if len(newEdges[0].Vertexes) > 1: # not circle
+ # print "nextCoordinate: ", nextCoordinate
+ # if len(newEdges[0].Vertexes) > 1: # not circle
for j, edge in enumerate(edges):
- #for j in range (len(edges)):
- #print "compare to: ", edges[j].Curve.StartPoint, "/" , edges[j].Curve.EndPoint
- #if edges[j].Curve.StartPoint == nextCoordinate:
+ # for j in range (len(edges)):
+ # print "compare to: ", edges[j].Curve.StartPoint, "/" , edges[j].Curve.EndPoint
+ # if edges[j].Curve.StartPoint == nextCoordinate:
if show_data:
- say(distance(edges[j].Vertexes[-1].Point, nextCoordinate))
- say(distance(edges[j].Vertexes[0].Point, nextCoordinate))
- #if edges[j].Vertexes[-1].Point == nextCoordinate:
+ say(distance(edge.Vertexes[-1].Point, nextCoordinate))
+ say(distance(edge.Vertexes[0].Point, nextCoordinate))
+ # if edges[j].Vertexes[-1].Point == nextCoordinate:
# sayw(distance(edges[j].Vertexes[-1].Point, nextCoordinate))
- # sayw(distance(edges[j].Vertexes[0].Point, nextCoordinate))
- if distance(edges[j].Vertexes[-1].Point, nextCoordinate)<=edge_tolerance:
- #if edges[j].Vertexes[-1].Point != nextCoordinate:
- if distance(edges[j].Vertexes[-1].Point, nextCoordinate)>edge_tolerance_warning:
- sayerr('non coincident edges:\n'+str(nextCoordinate)+';'+str(edges[j].Vertexes[-1].Point))
- nextCoordinate = edges[j].Vertexes[0].Point
+ # sayw(distance(edges[j].Vertexes[0].Point, nextCoordinate))
+ if distance(edge.Vertexes[-1].Point, nextCoordinate) <= edge_tolerance:
+ # if edges[j].Vertexes[-1].Point != nextCoordinate:
+ if distance(edge.Vertexes[-1].Point, nextCoordinate) > edge_tolerance_warning:
+ sayerr(
+ "non coincident edges:\n"
+ + str(nextCoordinate)
+ + ";"
+ + str(edge.Vertexes[-1].Point),
+ )
+ nextCoordinate = edge.Vertexes[0].Point
newEdges.append(edges.pop(j))
loopcounter = 0
break
- #elif edges[j].Vertexes[0].Point == nextCoordinate:
- elif distance(edges[j].Vertexes[0].Point, nextCoordinate)<=edge_tolerance:
- #if edges[j].Vertexes[0].Point != nextCoordinate:
- if distance(edges[j].Vertexes[0].Point, nextCoordinate)>edge_tolerance_warning:
- sayerr('non coincident edges:\n'+str(nextCoordinate)+';'+str(edges[j].Vertexes[0].Point))
- nextCoordinate = edges[j].Vertexes[-1].Point
+ # elif edges[j].Vertexes[0].Point == nextCoordinate:
+ if distance(edge.Vertexes[0].Point, nextCoordinate) <= edge_tolerance:
+ # if edges[j].Vertexes[0].Point != nextCoordinate:
+ if distance(edge.Vertexes[0].Point, nextCoordinate) > edge_tolerance_warning:
+ sayerr(
+ "non coincident edges:\n" + str(nextCoordinate) + ";" + str(edge.Vertexes[0].Point),
+ )
+ nextCoordinate = edge.Vertexes[-1].Point
newEdges.append(edges.pop(j))
loopcounter = 0
break
if show_data:
- say ("first c" + str(firstCoordinate)); say(' '); say ("last c" + str(nextCoordinate))
- #if nextCoordinate == firstCoordinate:
- if distance(firstCoordinate, nextCoordinate)<=edge_tolerance:
- say('2d closed path')
- try: # maui
- #say('\ntrying wire & face')
- #newEdges_old=newEdges
+ say("first c" + str(firstCoordinate))
+ say(" ")
+ say("last c" + str(nextCoordinate))
+ # if nextCoordinate == firstCoordinate:
+ if distance(firstCoordinate, nextCoordinate) <= edge_tolerance:
+ say("2d closed path")
+ try: # maui
+ # say('\ntrying wire & face')
+ # newEdges_old=newEdges
## newEdges = Part.Wire(newEdges)
- #say('trying face')
+ # say('trying face')
## newEdges = Part.Face(newEdges)
- #newEdges = OpenSCAD2DgeomMau.edgestofaces(newEdges)
- newEdges = OSCD2Dg_edgestofaces(newEdges,3 , edge_tolerance)
- newEdges.check() # reports errors
- newEdges.fix(0,0,0)
- #say('done')
- #newEdges.translate(Base.Vector(0,0,-totalHeight))
+ # newEdges = OpenSCAD2DgeomMau.edgestofaces(newEdges)
+ newEdges = OSCD2Dg_edgestofaces(newEdges, 3, edge_tolerance)
+ newEdges.check() # reports errors
+ newEdges.fix(0, 0, 0)
+ # say('done')
+ # newEdges.translate(Base.Vector(0,0,-totalHeight))
if show_shapes:
Part.show(newEdges)
- #newEdges = newEdges.extrude(Base.Vector(0,0,totalHeight))
+ # newEdges = newEdges.extrude(Base.Vector(0,0,totalHeight))
PCBs.append(newEdges)
- if (len(edges)>0):
- newEdges = [];
+ if len(edges) > 0:
+ newEdges = []
newEdges.append(edges.pop(0))
nextCoordinate = newEdges[0].Vertexes[0].Point
firstCoordinate = newEdges[0].Vertexes[-1].Point
- except Part.OCCError: # Exception: #
+ except Part.OCCError: # Exception: #
say("error in creating PCB")
stop
-
+
if loopcounter == 2:
say("*** omitting PCBs because there was a not closed loop in your edge lines ***")
- say("*** have a look at position x=" + str(nextCoordinate.x) + "mm, y=" + str(nextCoordinate.y) + "mm ***")
- say('pcb edge not closed')
+ say(
+ "*** have a look at position x="
+ + str(nextCoordinate.x)
+ + "mm, y="
+ + str(nextCoordinate.y)
+ + "mm ***",
+ )
+ say("pcb edge not closed")
QtGui.QApplication.restoreOverrideCursor()
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical,
- 'Error in creating Board Edge ."+"\r\n"',
- """pcb edge not closed
review your Board Edges in Kicad!
position x=""" + str(nextCoordinate.x) + 'mm, y=' + str(-nextCoordinate.y) + 'mm')
+ diag = QtGui.QMessageBox(
+ QtGui.QMessageBox.Icon.Critical,
+ 'Error in creating Board Edge ."+"\r\n"',
+ """pcb edge not closed
review your Board Edges in Kicad!
position x="""
+ + str(nextCoordinate.x)
+ + "mm, y="
+ + str(-nextCoordinate.y)
+ + "mm",
+ )
diag.setWindowModality(QtCore.Qt.ApplicationModal)
diag.exec_()
FreeCADGui.activeDocument().activeView().viewTop()
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- stop #maui
+ stop # maui
if disable_cutting:
FreeCADGui.activeDocument().activeView().viewTop()
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- stop #maui
- #say (PCBs)
+ stop # maui
+ # say (PCBs)
## doc = FreeCAD.activeDocument()
## #outline = []
## for f in PCBs:
## Part.show(f)
## PCB_Sketch= FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Sketch')
- ## FreeCAD.activeDocument().Sketch.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(0.000000,0.000000,0.000000,1.000000))
+ ## FreeCAD.activeDocument().Sketch.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(0.000000,0.000000,0.000000,1.000000))
## for s in doc.Objects:
## #for f in PCBs:
## if 'Part' in s.TypeId: #Part.show(s)
@@ -13470,96 +14542,99 @@ def make_gr_arc_obj (a,pa):
## for wire in wires[0:1]:
## Draft.makeSketch([wire],addTo=PCB_Sketch)
## for wire in wires:
- ## FreeCAD.ActiveDocument.removeObject(wire.Name)
+ ## FreeCAD.ActiveDocument.removeObject(wire.Name)
## FreeCAD.ActiveDocument.recompute()
- #for f in PCBs:
+ # for f in PCBs:
# Part.hide(f)
- ##FreeCADGui.SendMsgToActiveView("ViewFit")
+ ##FreeCADGui.SendMsgToActiveView("ViewFit")
##stop
-
- maxLenght=0
- idx=0
- external_idx=idx
+
+ maxLenght = 0
+ idx = 0
+ external_idx = idx
for extruded in PCBs:
- #search for orientation of each pcb in 3d space, save it (no transformation yet!)
- angle = 0;
- axis = Base.Vector(0,0,1)
- position = Base.Vector(0,0,0)
+ # search for orientation of each pcb in 3d space, save it (no transformation yet!)
+ Base.Vector(0, 0, 1)
+ Base.Vector(0, 0, 0)
if show_shapes:
Part.show(extruded)
- #extrude_XLenght=FreeCAD.ActiveDocument.ActiveObject.Shape.BoundBox.XLength
+ # extrude_XLenght=FreeCAD.ActiveDocument.ActiveObject.Shape.BoundBox.XLength
# extrude_XLenght=extruded.Length #perimeter
- extrude_XLenght=extruded.BoundBox.XLength
- #extrude_XLenght=FreeCAD.ActiveDocument.ActiveObject.Shape.Edges.Length
+ extrude_XLenght = extruded.BoundBox.XLength
+ # extrude_XLenght=FreeCAD.ActiveDocument.ActiveObject.Shape.Edges.Length
if maxLenght < extrude_XLenght:
maxLenght = extrude_XLenght
- external_idx=idx
- #say('XLenght='+str(extrude_XLenght))
- idx=idx+1
- say('max Length='+str(maxLenght)+' index='+str(external_idx))
+ external_idx = idx
+ # say('XLenght='+str(extrude_XLenght))
+ idx = idx + 1
+ say("max Length=" + str(maxLenght) + " index=" + str(external_idx))
try:
- cut_base=PCBs[external_idx]
+ cut_base = PCBs[external_idx]
except:
say("*** omitting PCBs because there was a not closed loop in your edge lines ***")
- say('pcb edge not closed')
+ say("pcb edge not closed")
QtGui.QApplication.restoreOverrideCursor()
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical,
- 'Error in creating Board Edge ."+"\r\n"',
- """pcb edge not closed
review your Board Edges in Kicad!
""")
+ diag = QtGui.QMessageBox(
+ QtGui.QMessageBox.Icon.Critical,
+ 'Error in creating Board Edge ."+"\r\n"',
+ """pcb edge not closed
review your Board Edges in Kicad!
""",
+ )
diag.setWindowModality(QtCore.Qt.ApplicationModal)
diag.exec_()
FreeCADGui.activeDocument().activeView().viewTop()
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- stop #maui
- i=0
- for i in range (len(PCBs)):
- if i!=external_idx:
- cutter=PCBs[i]
- cut_base=cut_base.cut(cutter)
+ stop # maui
+ i = 0
+ for i in range(len(PCBs)):
+ if i != external_idx:
+ cutter = PCBs[i]
+ cut_base = cut_base.cut(cutter)
if test_extrude:
- cut_base = cut_base.extrude(Base.Vector(0,0,totalHeight))
+ cut_base = cut_base.extrude(Base.Vector(0, 0, totalHeight))
if show_shapes:
Part.show(cut_base)
- #cut_base_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #say('Alive1')
- if len(PCBs)==1:
+ # cut_base_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ # say('Alive1')
+ if len(PCBs) == 1:
cut_base = PCBs[0]
if test_extrude:
- cut_base = cut_base.extrude(Base.Vector(0,0,totalHeight))
+ cut_base = cut_base.extrude(Base.Vector(0, 0, totalHeight))
if show_shapes:
Part.show(cut_base)
if show_shapes:
FreeCAD.activeDocument().removeObject("Shape")
###FreeCAD.ActiveDocument.recompute()
-
- if len(PCBs)==0:
- say('pcb edge not found')
+
+ if len(PCBs) == 0:
+ say("pcb edge not found")
QtGui.QApplication.restoreOverrideCursor()
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical,
- 'Error in creating Board Edge ."+"\r\n"',
- """pcb edge not closed
review your Board Edges in Kicad!
""")
+ diag = QtGui.QMessageBox(
+ QtGui.QMessageBox.Icon.Critical,
+ 'Error in creating Board Edge ."+"\r\n"',
+ """pcb edge not closed
review your Board Edges in Kicad!
""",
+ )
diag.setWindowModality(QtCore.Qt.ApplicationModal)
diag.exec_()
FreeCADGui.activeDocument().activeView().viewTop()
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- stop #maui
+ stop # maui
FreeCAD.ActiveDocument.recompute()
FreeCADGui.activeDocument().activeView().viewTop()
##FreeCADGui.SendMsgToActiveView("ViewFit")
if create_pcb_basic:
## experimental technique for getting the pcb edge in case of large quantity of segments
## To be completed
- if (len(edges)==0) and (len(PCBs)==0):
+ if (len(edges) == 0) and (len(PCBs) == 0):
sayw("no PCBs found")
stop
else:
- sayw('creating pcb from edges without constraints')
- #N_edges = []
- #for s in edges:
+ sayw("creating pcb from edges without constraints")
+ # N_edges = []
+ # for s in edges:
# N_edges.extend(s.Edges)
- #if len(edges) > (100):
+ # if len(edges) > (100):
# FreeCAD.Console.PrintMessage(str(len(edges))+" edges to join\n")
# if FreeCAD.GuiUp:
# from PySide import QtGui
@@ -13572,71 +14647,77 @@ def make_gr_arc_obj (a,pa):
# if res == QtGui.QMessageBox.Cancel:
# FreeCAD.Console.PrintMessage("Aborted\n")
# return
-
+
if 0:
- newEdges = OSCD2Dg_edgestofaces(edges,3 , edge_tolerance)
+ newEdges = OSCD2Dg_edgestofaces(edges, 3, edge_tolerance)
Part.show(newEdges)
stop
if 0:
## from importDXF
- shapes = DraftGeomUtils.findWires(edges) #N_edges)
- def addObject(shape,name="Shape",layer=None):
+ shapes = DraftGeomUtils.findWires(edges) # N_edges)
+
+ def addObject(shape, name="Shape", layer=None):
"adds a new object to the document with passed arguments"
- if isinstance(shape,Part.Shape):
- #say(doc.Name)
- #stop
- newob=doc.addObject("Part::Feature",name)
+ if isinstance(shape, Part.Shape):
+ # say(doc.Name)
+ # stop
+ newob = doc.addObject("Part::Feature", name)
newob.Shape = shape
else:
newob = shape
- #if layer:
+ # if layer:
# lay=locateLayer(layer)
# lay.addObject(newob)
- #formatObject(newob)
+ # formatObject(newob)
return newob
- shapes_list=[]
+
+ shapes_list = []
for s in shapes:
newob = addObject(s)
shapes_list.append(newob)
-
- WireSketch = FreeCAD.activeDocument().addObject('Sketcher::SketchObject','WireSketch')
- shapes = Draft.makeSketch(shapes,autoconstraints=True,addTo=WireSketch)
- FreeCAD.ActiveDocument.addObject("Part::Face", "Face_WireSketch").Sources = (FreeCAD.ActiveDocument.WireSketch, )
+
+ WireSketch = FreeCAD.activeDocument().addObject("Sketcher::SketchObject", "WireSketch")
+ shapes = Draft.makeSketch(shapes, autoconstraints=True, addTo=WireSketch)
+ FreeCAD.ActiveDocument.addObject("Part::Face", "Face_WireSketch").Sources = (
+ FreeCAD.ActiveDocument.WireSketch,
+ )
if 0:
- FreeCAD.activeDocument().addObject("Part::Compound","ShapesCompound")
+ FreeCAD.activeDocument().addObject("Part::Compound", "ShapesCompound")
FreeCAD.activeDocument().ShapesCompound.Links = shapes_list
- FreeCAD.ActiveDocument.addObject("Part::Face", "Face_Compound").Sources = (FreeCAD.ActiveDocument.ShapesCompound, )
+ FreeCAD.ActiveDocument.addObject("Part::Face", "Face_Compound").Sources = (
+ FreeCAD.ActiveDocument.ShapesCompound,
+ )
FreeCAD.ActiveDocument.recompute()
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
stop
- #fusion_wire = edges[0]
- #for no, e in enumerate(edges):
+ # fusion_wire = edges[0]
+ # for no, e in enumerate(edges):
# no += 1
# if no > 1:
# fusion_wire = fusion_wire.fuse(e)
# Part.show(fusion_wire)
-
+
for e in edges:
Part.show(e)
stop
- #w_pcb = Part.Wire(edges)
- #Part.show(w_pcb)
-
+ # w_pcb = Part.Wire(edges)
+ # Part.show(w_pcb)
+
say_time()
-
- #cut_base = cut_base.extrude(Base.Vector(0,0,totalHeight)) # test_face
- #Part.show(cut_base) #test Sketch
- #stop
- #PCB_Sketch= FreeCAD.activeDocument().addObject('Sketcher::SketchObject','PCB_Sketch')
- #FreeCAD.activeDocument().PCB_Sketch.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(0.000000,0.000000,0.000000,1.000000))
+
+ # cut_base = cut_base.extrude(Base.Vector(0,0,totalHeight)) # test_face
+ # Part.show(cut_base) #test Sketch
+ # stop
+ # PCB_Sketch= FreeCAD.activeDocument().addObject('Sketcher::SketchObject','PCB_Sketch')
+ # FreeCAD.activeDocument().PCB_Sketch.Placement = App.Placement(App.Vector(0.000000,0.000000,0.000000),App.Rotation(0.000000,0.000000,0.000000,1.000000))
doc = FreeCAD.activeDocument()
- #wires,_faces = Draft.downgrade(cut_base,delete=False)
- #edges=[]
- #for f in cut_base.Faces:
+ # wires,_faces = Draft.downgrade(cut_base,delete=False)
+ # edges=[]
+ # for f in cut_base.Faces:
# #print f.Edges
# edges.append(f.Edges)
- #for e in edges:
+ # for e in edges:
# print e
# print e.Vertexes.Point[0]
# print e.Vertexes.Point[-1]
@@ -13644,37 +14725,37 @@ def addObject(shape,name="Shape",layer=None):
## print w
## Draft.makeSketch([w], autoconstraints = True, addTo=PCB_Sketch)
## PCB_Sketch.touch()
- #Part.Wire (edges)
- #print edges
- #for wire in wires:
+ # Part.Wire (edges)
+ # print edges
+ # for wire in wires:
# sayw(wire.Label)
# Draft.makeSketch([wire], autoconstraints = True, addTo=PCB_Sketch)
# #Draft.makeSketch([wire], autoconstraints = False, addTo=PCB_Sketch)
# PCB_Sketch.touch()
- if 0: #old Sketch method
+ if 0: # old Sketch method
FreeCAD.ActiveDocument.recompute()
- wires,_faces = Draft.downgrade(FreeCAD.ActiveDocument.Shape,delete=False)
+ wires, _faces = Draft.downgrade(FreeCAD.ActiveDocument.Shape, delete=False)
FreeCAD.ActiveDocument.recompute()
for wire in wires:
- Draft.makeSketch([wire],autoconstraints=True, addTo=PCB_Sketch)
- #makeSketch_FC_016([wire],autoconstraints=True, addTo=PCB_Sketch)
+ Draft.makeSketch([wire], autoconstraints=True, addTo=PCB_Sketch)
+ # makeSketch_FC_016([wire],autoconstraints=True, addTo=PCB_Sketch)
PCB_Sketch.touch()
- #stop
+ # stop
for wire in wires:
- FreeCAD.ActiveDocument.removeObject(wire.Name)
-
- #Draft.makeSketch(FreeCAD.ActiveDocument.Wire,autoconstraints=False, addTo=PCB_Sketch)
- #FreeCAD.ActiveDocument.recompute()
- #FreeCAD.ActiveDocument.removeObject(FreeCAD.ActiveDocument.Wire.Name)
+ FreeCAD.ActiveDocument.removeObject(wire.Name)
+
+ # Draft.makeSketch(FreeCAD.ActiveDocument.Wire,autoconstraints=False, addTo=PCB_Sketch)
+ # FreeCAD.ActiveDocument.recompute()
+ # FreeCAD.ActiveDocument.removeObject(FreeCAD.ActiveDocument.Wire.Name)
FreeCAD.ActiveDocument.recompute()
-
- #s_name=shift_sketch(PCB_Sketch_draft.Name, [-100,-100])
- #add_constraints(s_name)
- #stop
- #for s in doc.Objects:
+
+ # s_name=shift_sketch(PCB_Sketch_draft.Name, [-100,-100])
+ # add_constraints(s_name)
+ # stop
+ # for s in doc.Objects:
##for f in PCBs:
- # if 'Part' in s.TypeId:
- # #if cut_base.Name in s.Name:
+ # if 'Part' in s.TypeId:
+ # #if cut_base.Name in s.Name:
# #Part.show(s)
# wires,_faces = Draft.downgrade(s,delete=False)
# #wires,_faces = Draft.downgrade(s,delete=True)
@@ -13685,7 +14766,7 @@ def addObject(shape,name="Shape",layer=None):
# # print f.Edges
# for f in s.Faces:
# print f.Edges
- #
+ #
# for wire in wires:
# #sayw(wire.Label)
# Draft.makeSketch([wire], autoconstraints = True, addTo=PCB_Sketch)
@@ -13693,419 +14774,444 @@ def addObject(shape,name="Shape",layer=None):
# PCB_Sketch.touch()
# stop
# for wire in wires:
- # FreeCAD.ActiveDocument.removeObject(wire.Name)
+ # FreeCAD.ActiveDocument.removeObject(wire.Name)
# FreeCAD.ActiveDocument.recompute()
- #Part.show(cut_base)
- #stop #maui
+ # Part.show(cut_base)
+ # stop #maui
## to check to load models inside loop modules
- #if m.layer == 'F.Cu': # top
+ # if m.layer == 'F.Cu': # top
# side = "Top"
- #else:
+ # else:
# side = "Bottom"
# m_angle *= -1 ##bottom 3d model rotation
- # say(m_angle)
+ # say(m_angle)
say("start cutting")
get_time()
- t1=(running_time)
- if not use_AppPart: #old method slower for FC016,015
+ t1 = running_time
+ if not use_AppPart: # old method slower for FC016,015
if holes_solid:
- #HoleList = getPads(board_elab,pcbThickness)
- say('generating solid holes')
+ # HoleList = getPads(board_elab,pcbThickness)
+ say("generating solid holes")
else:
- say('generating flat holes')
+ say("generating flat holes")
##HoleList = getPads_flat(board_elab)
- #say('alive-getting holes')
- #stop
- if len(HoleList)>0:
- #cut_base = FreeCAD.ActiveDocument.getObject(cut_base_name).Shape
- #cut_base_name=FreeCAD.ActiveDocument.ActiveObject
- #cut_base_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #say(cut_base)
+ # say('alive-getting holes')
+ # stop
+ if len(HoleList) > 0:
+ # cut_base = FreeCAD.ActiveDocument.getObject(cut_base_name).Shape
+ # cut_base_name=FreeCAD.ActiveDocument.ActiveObject
+ # cut_base_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ # say(cut_base)
for drill in HoleList:
- #say("Cutting hole inside outline")
- #Part.show(drill)
- #say(drill)
+ # say("Cutting hole inside outline")
+ # Part.show(drill)
+ # say(drill)
if holes_solid:
drill = Part.makeSolid(drill)
if show_shapes:
Part.show(drill)
- cut_base=cut_base.cut(drill)
+ cut_base = cut_base.cut(drill)
else:
- #face = cut_base
+ # face = cut_base
cut_base = cut_base
- else:
- sayw('using hierarchy container')
- if len(HoleList)>0:
+ else:
+ sayw("using hierarchy container")
+ if len(HoleList) > 0:
if holes_solid:
- #HoleList = getPads(board_elab,pcbThickness)
- say('generating solid holes')
+ # HoleList = getPads(board_elab,pcbThickness)
+ say("generating solid holes")
else:
- say('generating flat holes')
- dlo=[]
- shapes=[];s_names=[]
- #for drill in HoleList:
+ say("generating flat holes")
+ shapes = []
+ s_names = []
+ # for drill in HoleList:
# if holes_solid:
# drill = Part.makeSolid(drill)
- #Part.show(drill)
- #dlo.append(drill)
- #shapes=[];s_names=[]
+ # Part.show(drill)
+ # dlo.append(drill)
+ # shapes=[];s_names=[]
##for o in FreeCAD.ActiveDocument.Objects:
## if 'Shape' in o.Name:
## dlo.append(FreeCAD.ActiveDocument.getObject(o.Name))
## shapes.append(o.Shape)
## s_names.append(o.Name)
- shapes=HoleList
- #stop
+ shapes = HoleList
+ # stop
##https://forum.freecadweb.org/viewtopic.php?t=18179&start=30
- #multifuse
- shape_base=shapes[0]
- shapes=shapes[1:]
- #fc_016=True
- if len(HoleList)>1: #more than one drill
+ # multifuse
+ shape_base = shapes[0]
+ shapes = shapes[1:]
+ # fc_016=True
+ if len(HoleList) > 1: # more than one drill
shape = shape_base.fuse(shapes)
- #shape = Part.makeCompound(shapes) #this could create issues on cutting
- else: #one drill ONLY
+ # shape = Part.makeCompound(shapes) #this could create issues on cutting
+ else: # one drill ONLY
shape = shape_base
if extrude_holes:
- shape.Placement.Base.z+=0.05 # fixing coplanar shapes cut
- shape=shape.extrude(FreeCAD.Base.Vector(0, 0, -totalHeight-0.1)) # fixing coplanar shapes cut
+ shape.Placement.Base.z += 0.05 # fixing coplanar shapes cut
+ shape = shape.extrude(FreeCAD.Base.Vector(0, 0, -totalHeight - 0.1)) # fixing coplanar shapes cut
if show_shapes:
- Part.show(shape)
- Part.show(cut_base) #test_face
- #stop
+ Part.show(shape)
+ Part.show(cut_base) # test_face
+ # stop
test_face_gen = False
if test_face_gen:
- Part.show(cut_base) #test_face
- Part.show(shape) #test_face
+ Part.show(cut_base) # test_face
+ Part.show(shape) # test_face
stop
try:
cut_base = cut_base.cut(shape)
except:
say("*** omitting PCBs because there was a not closed loop in your edge lines ***")
- say('pcb edge not closed')
+ say("pcb edge not closed")
QtGui.QApplication.restoreOverrideCursor()
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical,
- 'Error in creating Board Edge ."+"\r\n"',
- """pcb edge not closed
review your Board Edges in Kicad!
or try to fix it with Constrainator""")
+ diag = QtGui.QMessageBox(
+ QtGui.QMessageBox.Icon.Critical,
+ 'Error in creating Board Edge ."+"\r\n"',
+ """pcb edge not closed
review your Board Edges in Kicad!
or try to fix it with Constrainator""",
+ )
diag.setWindowModality(QtCore.Qt.ApplicationModal)
diag.exec_()
FreeCADGui.activeDocument().activeView().viewTop()
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- stop #maui
- #Part.show(cut_base)
- #stop
+ stop # maui
+ # Part.show(cut_base)
+ # stop
for s in s_names:
- #Part.show(s)
- FreeCAD.ActiveDocument.removeObject(s) #test_face
+ # Part.show(s)
+ FreeCAD.ActiveDocument.removeObject(s) # test_face
FreeCAD.ActiveDocument.recompute()
- #stop
- #say_time()
-
+ # stop
+ # say_time()
+
else:
- #face = cut_base
- sayw('pcb without holes')
+ # face = cut_base
+ sayw("pcb without holes")
# Part.show(cut_base) #test_face
# f0 = cut_base.Faces[0]
# Part.show(f0)
- #cut_base = cut_base
-
- #else:
+ # cut_base = cut_base
+
+ # else:
# #face = cut_base
# try:
# cut_base = cut_base
# except:
# cut_base = FreeCAD.ActiveDocument.getObject('PCB_Sketch_draft') #s_PCB_Sketch_draft
- #if lyr != 'Edge.Cuts':
- # cut_base.Label=lyr+'-Sketch'
- #FreeCADGui.SendMsgToActiveView("ViewFit")
+ # if lyr != 'Edge.Cuts':
+ # cut_base.Label=lyr+'-Sketch'
+ # FreeCADGui.SendMsgToActiveView("ViewFit")
# ##if len(HoleList)>0:
# ## #face = cut_base.cut(Part.makeCompound(HoleList))
# ## cut_base = cut_base.cut(Part.makeCompound(HoleList)) ###VERY fast but failing when overlapping of pads
get_time()
- say('cutting time ' +str(round(running_time-t1,3)))
-
- if lyr == 'Edge.Cuts':
- pcb_name=u'Pcb'+fname_sfx
- #doc_outline=doc.addObject("Part::Feature","Pcb")
- doc_outline=doc.addObject("Part::Feature",pcb_name)
- pcb_name=FreeCAD.ActiveDocument.ActiveObject.Name
- pcb_board=FreeCAD.ActiveDocument.ActiveObject
+ say("cutting time " + str(round(running_time - t1, 3)))
+
+ if lyr == "Edge.Cuts":
+ pcb_name = "Pcb" + fname_sfx
+ # doc_outline=doc.addObject("Part::Feature","Pcb")
+ doc_outline = doc.addObject("Part::Feature", pcb_name)
+ pcb_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ pcb_board = FreeCAD.ActiveDocument.ActiveObject
try:
- #doc_outline.Shape=cut_base.extrude(Base.Vector(0,0,-totalHeight))
+ # doc_outline.Shape=cut_base.extrude(Base.Vector(0,0,-totalHeight))
f0 = cut_base.Faces[0]
- s0 = f0.extrude(Base.Vector(0,0,-totalHeight))
+ s0 = f0.extrude(Base.Vector(0, 0, -totalHeight))
s = s0
for f in cut_base.Faces[1:]:
- #f0 = f0.union(f)
- s1 = f.extrude(Base.Vector(0,0,-totalHeight))
+ # f0 = f0.union(f)
+ s1 = f.extrude(Base.Vector(0, 0, -totalHeight))
s = s.fuse(s1)
- doc_outline.Shape=s
- #doc_outline.Shape=f0.extrude(Base.Vector(0,0,-totalHeight))
- #doc_outline.Shape=cut_base.Faces[0].extrude(Base.Vector(0,0,-totalHeight))
+ doc_outline.Shape = s
+ # doc_outline.Shape=f0.extrude(Base.Vector(0,0,-totalHeight))
+ # doc_outline.Shape=cut_base.Faces[0].extrude(Base.Vector(0,0,-totalHeight))
except:
- #doc.removeObject("Pcb")
+ # doc.removeObject("Pcb")
doc.removeObject(pcb_name)
say("*** omitting PCBs because there was a not closed loop in your edge lines ***")
- say('pcb edge not closed')
+ say("pcb edge not closed")
QtGui.QApplication.restoreOverrideCursor()
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical,
- 'Error in creating Board Edge ."+"\r\n"',
- """pcb edge not closed
review your Board Edges in Kicad!
or try to fix it with Constrainator""")
+ diag = QtGui.QMessageBox(
+ QtGui.QMessageBox.Icon.Critical,
+ 'Error in creating Board Edge ."+"\r\n"',
+ """pcb edge not closed
review your Board Edges in Kicad!
or try to fix it with Constrainator""",
+ )
diag.setWindowModality(QtCore.Qt.ApplicationModal)
diag.exec_()
FreeCADGui.activeDocument().activeView().viewTop()
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- stop #maui
- #stop
- #tobechecked
- #try:
+ stop # maui
+ # stop
+ # tobechecked
+ # try:
# FreeCAD.activeDocument().removeObject('Shape') #removing base shape
- #except:
+ # except:
# sayw('Shape already removed')
- #cut_base=cut_base.extrude(Base.Vector(0,0,-pcbThickness))
- #Part.show(cut_base)
+ # cut_base=cut_base.extrude(Base.Vector(0,0,-pcbThickness))
+ # Part.show(cut_base)
if simplifyComSolid:
- faces=[]
- for f in pcb_board.Shape.Faces:
- faces.append(f)
+ faces = list(pcb_board.Shape.Faces)
try:
_ = Part.Shell(faces)
- _=Part.Solid(_)
+ _ = Part.Solid(_)
FreeCAD.ActiveDocument.removeObject(pcb_name)
- #doc.addObject('Part::Feature','Pcb').Shape=_
- doc.addObject('Part::Feature',pcb_name).Shape=_
- pcb_name=FreeCAD.ActiveDocument.ActiveObject.Name
- pcb_board=FreeCAD.ActiveDocument.ActiveObject
+ # doc.addObject('Part::Feature','Pcb').Shape=_
+ doc.addObject("Part::Feature", pcb_name).Shape = _
+ pcb_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ pcb_board = FreeCAD.ActiveDocument.ActiveObject
except:
- sayerr('error in simplifying compsolid')
-
+ sayerr("error in simplifying compsolid")
+
# simple_pcb=doc.addObject("Part::Feature","simple_Pcb")
# simple_pcb.Shape=pcb_board.Shape
# spcb=pcb_board.Shape
# Part.show(spcb)
-
- #FreeCAD.ActiveDocument.ActiveObject.Label ="Pcb"
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (colr,colg,colb)
- #FreeCADGui.ActiveDocument.ActiveObject.Transparency = 20
- #if remove_pcbPad==True:
+
+ # FreeCAD.ActiveDocument.ActiveObject.Label ="Pcb"
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (colr, colg, colb)
+ # FreeCADGui.ActiveDocument.ActiveObject.Transparency = 20
+ # if remove_pcbPad==True:
# FreeCAD.activeDocument().removeObject(cut_base_name)
- #FreeCAD.activeDocument().removeObject(Holes_name)
- boardG_name='Board_Geoms'+fname_sfx
- board_name='Board'+fname_sfx
+ # FreeCAD.activeDocument().removeObject(Holes_name)
+ boardG_name = "Board_Geoms" + fname_sfx
+ board_name = "Board" + fname_sfx
if use_AppPart and not force_oldGroups and not use_LinkGroups:
## to evaluate to add App::Part hierarchy
- #sayw("creating hierarchy")
- doc.Tip = doc.addObject('App::Part',boardG_name)
- boardG= doc.ActiveObject
+ # sayw("creating hierarchy")
+ doc.Tip = doc.addObject("App::Part", boardG_name)
+ boardG = doc.ActiveObject
boardG.Label = boardG_name
try:
- boardG.License = ''
- boardG.LicenseURL = ''
+ boardG.License = ""
+ boardG.LicenseURL = ""
except:
pass
- grp=boardG
+ grp = boardG
if rmv_container is None or rmv_container is False:
- doc.Tip = doc.addObject('App::Part',board_name)
- board= doc.ActiveObject
+ doc.Tip = doc.addObject("App::Part", board_name)
+ board = doc.ActiveObject
board.Label = board_name
- #FreeCAD.ActiveDocument.getObject("Step_Virtual_Models").addObject(impPart)
+ # FreeCAD.ActiveDocument.getObject("Step_Virtual_Models").addObject(impPart)
# doc.getObject(board_name).addObject(doc.getObject(boardG_name))
try:
- #doc.getObject(boardG_name).addObject(LCS)
+ # doc.getObject(boardG_name).addObject(LCS)
doc.getObject(board_name).addObject(LCS)
- LCS.MapMode = 'ObjectXY'
+ LCS.MapMode = "ObjectXY"
LCS.MapReversed = False
- LCS.Support = [(doc.getObject(board_name).Origin.OriginFeatures[0],'')]
+ LCS.Support = [(doc.getObject(board_name).Origin.OriginFeatures[0], "")]
except:
pass
doc.getObject(board_name).addObject(doc.getObject(boardG_name))
else:
try:
- #doc.getObject(boardG_name).addObject(LCS)
+ # doc.getObject(boardG_name).addObject(LCS)
doc.getObject(board_name).addObject(LCS)
- LCS.MapMode = 'ObjectXY'
+ LCS.MapMode = "ObjectXY"
LCS.MapReversed = False
- LCS.Support = [(doc.getObject(board_name).Origin.OriginFeatures[0],'')]
+ LCS.Support = [(doc.getObject(board_name).Origin.OriginFeatures[0], "")]
except:
pass
doc.getObject(boardG_name).addObject(doc.getObject(pcb_name))
- #FreeCADGui.activeView().setActiveObject('Board_Geoms', doc.Board_Geoms)
+ # FreeCADGui.activeView().setActiveObject('Board_Geoms', doc.Board_Geoms)
## end hierarchy
elif use_LinkGroups:
- doc.Tip = doc.addObject('App::LinkGroup',boardG_name)
- boardG= doc.ActiveObject
+ doc.Tip = doc.addObject("App::LinkGroup", boardG_name)
+ boardG = doc.ActiveObject
boardG.Label = boardG_name
- grp=boardG_name
+ grp = boardG_name
if rmv_container is None or rmv_container is False:
- doc.Tip = doc.addObject('App::LinkGroup',board_name)
- board= doc.ActiveObject
+ doc.Tip = doc.addObject("App::LinkGroup", board_name)
+ board = doc.ActiveObject
board.Label = board_name
- #FreeCAD.ActiveDocument.getObject("Step_Virtual_Models").addObject(impPart)
+ # FreeCAD.ActiveDocument.getObject("Step_Virtual_Models").addObject(impPart)
# doc.getObject("Board").addObject(doc.Board_Geoms)
- #doc.getObject('Board_Geoms').adjustRelativeLinks(doc.getObject('Board'))
+ # doc.getObject('Board_Geoms').adjustRelativeLinks(doc.getObject('Board'))
# doc.getObject(board_name).ViewObject.dropObject(doc.getObject(boardG_name),doc.getObject(boardG_name),'',[])
try:
- #LCS.adjustRelativeLinks(doc.getObject('Board_Geoms'))
- #doc.getObject(boardG_name).ViewObject.dropObject(LCS,LCS,'',[])
- doc.getObject(board_name).ViewObject.dropObject(LCS,LCS,'',[])
+ # LCS.adjustRelativeLinks(doc.getObject('Board_Geoms'))
+ # doc.getObject(boardG_name).ViewObject.dropObject(LCS,LCS,'',[])
+ doc.getObject(board_name).ViewObject.dropObject(LCS, LCS, "", [])
# LinkGroups don't have 'Origin' Feature
# LCS.MapMode = 'ObjectXY'
# LCS.MapReversed = False
# LCS.Support = [(doc.getObject(board_name).Origin.OriginFeatures[0],'')]
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(LCS)
- FreeCADGui.runCommand('Std_ToggleVisibility',0)
- #stop
+ FreeCADGui.runCommand("Std_ToggleVisibility", 0)
+ # stop
except:
pass
- doc.getObject(board_name).ViewObject.dropObject(doc.getObject(boardG_name),doc.getObject(boardG_name),'',[])
+ doc.getObject(board_name).ViewObject.dropObject(
+ doc.getObject(boardG_name),
+ doc.getObject(boardG_name),
+ "",
+ [],
+ )
else:
try:
- #LCS.adjustRelativeLinks(doc.getObject('Board_Geoms'))
- #doc.getObject(boardG_name).ViewObject.dropObject(LCS,LCS,'',[])
- doc.getObject(board_name).ViewObject.dropObject(LCS,LCS,'',[])
+ # LCS.adjustRelativeLinks(doc.getObject('Board_Geoms'))
+ # doc.getObject(boardG_name).ViewObject.dropObject(LCS,LCS,'',[])
+ doc.getObject(board_name).ViewObject.dropObject(LCS, LCS, "", [])
# LinkGroups don't have 'Origin' Feature
# LCS.MapMode = 'ObjectXY'
# LCS.MapReversed = False
# LCS.Support = [(doc.getObject(board_name).Origin.OriginFeatures[0],'')]
FreeCADGui.Selection.clearSelection()
FreeCADGui.Selection.addSelection(LCS)
- FreeCADGui.runCommand('Std_ToggleVisibility',0)
- #stop
+ FreeCADGui.runCommand("Std_ToggleVisibility", 0)
+ # stop
except:
pass
FreeCADGui.Selection.clearSelection()
- #grp.addObject(pcb_board)
- #doc.getObject('Pcb').adjustRelativeLinks(doc.getObject('Board_Geoms'))
- #doc.getObject('Board_Geoms').ViewObject.dropObject(doc.getObject('Pcb'),None,'',[])
- doc.getObject(boardG_name).ViewObject.dropObject(doc.getObject(pcb_name),doc.getObject(pcb_name),'',[])
+ # grp.addObject(pcb_board)
+ # doc.getObject('Pcb').adjustRelativeLinks(doc.getObject('Board_Geoms'))
+ # doc.getObject('Board_Geoms').ViewObject.dropObject(doc.getObject('Pcb'),None,'',[])
+ doc.getObject(boardG_name).ViewObject.dropObject(
+ doc.getObject(pcb_name),
+ doc.getObject(pcb_name),
+ "",
+ [],
+ )
FreeCADGui.Selection.clearSelection()
- #FreeCADGui.activeView().setActiveObject('Board_Geoms', doc.Board_Geoms)
- ## end hierarchy
+ # FreeCADGui.activeView().setActiveObject('Board_Geoms', doc.Board_Geoms)
+ ## end hierarchy
else:
- #sayw("creating flat groups")
- grp=doc.addObject("App::DocumentObjectGroup", boardG_name)
+ # sayw("creating flat groups")
+ grp = doc.addObject("App::DocumentObjectGroup", boardG_name)
grp.addObject(pcb_board)
- #pcb_sk=FreeCAD.ActiveDocument.PCB_Sketch
- #grp.addObject(pcb_sk)
- #grp.addObject(doc_outline)
+ # pcb_sk=FreeCAD.ActiveDocument.PCB_Sketch
+ # grp.addObject(pcb_sk)
+ # grp.addObject(doc_outline)
pcb_bbx = doc.getObject(pcb_name).Shape.BoundBox
- say("pcb dimensions: ("+"{0:.2f}".format(pcb_bbx.XLength)+";"+"{0:.2f}".format(pcb_bbx.YLength)+";"+"{0:.2f}".format(pcb_bbx.ZLength)+")")
+ say(
+ "pcb dimensions: ("
+ + f"{pcb_bbx.XLength:.2f}"
+ + ";"
+ + f"{pcb_bbx.YLength:.2f}"
+ + ";"
+ + f"{pcb_bbx.ZLength:.2f}"
+ + ")",
+ )
say_time()
if k_index == 1:
FreeCAD.ActiveDocument.removeObject(ndsk.Name)
- #FreeCADGui.activeDocument().activeView().viewAxometric()
+ # FreeCADGui.activeDocument().activeView().viewAxometric()
FreeCADGui.activeDocument().activeView().viewTop()
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- #FreeCADGui.SendMsgToActiveView("ViewFit")
- #pads_found=getPadsList(content)
+ # FreeCADGui.SendMsgToActiveView("ViewFit")
+ # pads_found=getPadsList(content)
return PCB_Models, k_index
-
-###
+
+
+###
###
-#cmd open option
-args=sys.argv
-#say(args)
+# cmd open option
+args = sys.argv
+# say(args)
if len(args) >= 3:
-# #filename="./psu-fc-1.wrl"
- #path, fname = os.path.split(args[2])
- #export_board_2step=True
+ # #filename="./psu-fc-1.wrl"
+ # path, fname = os.path.split(args[2])
+ # export_board_2step=True
##sys.argv=""
ext = os.path.splitext(os.path.basename(args[2]))[1]
- fullfname=args[2]
- fname=os.path.splitext(os.path.basename(args[2]))[0]
- #say(filePath+' ');say(fname+' ');say(ext);
- fullFileName=fullfname+".kicad_pcb"
- fullFileNamefp=fullfname+".kicad_mod"
- fileName=fname+".kicad_pcb"
- fileNamefp=fname+".kicad_mod"
- #filePath = os.path.dirname(os.path.abspath(__file__))
+ fullfname = args[2]
+ fname = os.path.splitext(os.path.basename(args[2]))[0]
+ # say(filePath+' ');say(fname+' ');say(ext);
+ fullFileName = fullfname + ".kicad_pcb"
+ fullFileNamefp = fullfname + ".kicad_mod"
+ fileName = fname + ".kicad_pcb"
+ fileNamefp = fname + ".kicad_mod"
+ # filePath = os.path.dirname(os.path.abspath(__file__))
filePath = os.path.dirname(os.path.abspath(fullFileName))
filePathfp = os.path.dirname(os.path.abspath(fullFileName))
- #filePath = os.path.split(os.path.realpath(__file__))[0]
- say ('arg file path '+filePath)
- filefound=True
+ # filePath = os.path.split(os.path.realpath(__file__))[0]
+ say("arg file path " + filePath)
+ filefound = True
if filePath == "":
- filePath = u"."
+ filePath = "."
last_pcb_path = filePath
- print (last_pcb_path)
- #say(fullFileName)
+ print(last_pcb_path)
+ # say(fullFileName)
if os.path.exists(fullFileName):
- #say("opening "+ fullFileName)
- #cfgParsWrite(configFilePath)
- #cfg_update_all()
+ # say("opening "+ fullFileName)
+ # cfgParsWrite(configFilePath)
+ # cfg_update_all()
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
pg.SetString("last_pcb_path", make_string(last_pcb_path))
- original_filename=fullFileName
+ original_filename = fullFileName
onLoadBoard(fullFileName)
else:
- fullfilePath=filePath+os.sep+fname+".kicad_pcb"
- #say(fullfilePath)
+ fullfilePath = filePath + os.sep + fname + ".kicad_pcb"
+ # say(fullfilePath)
if os.path.exists(fullfilePath):
- #say("opening "+ fullfilePath)
- #cfgParsWrite(configFilePath)
- #cfg_update_all()
+ # say("opening "+ fullfilePath)
+ # cfgParsWrite(configFilePath)
+ # cfg_update_all()
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
pg.SetString("last_pcb_path", make_string(last_pcb_path))
- original_filename=fullfilePath
+ original_filename = fullfilePath
onLoadBoard(fullfilePath)
else:
- filefound=False
+ filefound = False
# sayw("missing "+ fullfilePath)
# sayw("missing "+ fullFileName)
# #say("error missing "+ fullfilePath)
# QtGui.QApplication.restoreOverrideCursor()
# reply = QtGui.QMessageBox.information(None,"Error ...","... missing \r\n"+ fullfilePath+"\r\n... missing \r\n"+ fullFileName)
- if filefound ==False:
+ if not filefound:
if os.path.exists(fullFileNamefp):
- #say("opening "+ fullFileName)
- #cfgParsWrite(configFilePath)
- #cfg_update_all()
+ # say("opening "+ fullFileName)
+ # cfgParsWrite(configFilePath)
+ # cfg_update_all()
import fps
+
fps.addfootprint(fullFileNamefp)
else:
- fullfilePath=filePath+os.sep+fname+".kicad_mod"
- #say(fullfilePath)
+ fullfilePath = filePath + os.sep + fname + ".kicad_mod"
+ # say(fullfilePath)
if os.path.exists(fullfilePath):
- fp_loaded= False
+ fp_loaded = False
doc = FreeCAD.ActiveDocument
if doc is not None:
for o in doc.Objects:
- if hasattr(o, 'Label'):
- if o.Label.endswith('_fp'):
- fp_loaded= True
- #say("opening "+ fullfilePath)
- #cfgParsWrite(configFilePath)
- #cfg_update_all()
- #print(fp_loaded)
+ if hasattr(o, "Label") and o.Label.endswith("_fp"):
+ fp_loaded = True
+ # say("opening "+ fullfilePath)
+ # cfgParsWrite(configFilePath)
+ # cfg_update_all()
+ # print(fp_loaded)
if not (fp_loaded):
import fps
+
fps.addfootprint(fullfilePath)
# onLoadFootprint(fullfilePath)
else:
- sayw("missing "+ fullfilePath)
- sayw("missing "+ fullFileName)
- #say("error missing "+ fullfilePath)
+ sayw("missing " + fullfilePath)
+ sayw("missing " + fullFileName)
+ # say("error missing "+ fullfilePath)
if 0:
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Error ...","... missing \r\n"+ fullfilePath+"\r\n... missing \r\n"+ fullFileName)
- #
+ reply = QtGui.QMessageBox.information(
+ None,
+ "Error ...",
+ "... missing \r\n" + fullfilePath + "\r\n... missing \r\n" + fullFileName,
+ )
###
-#QtGui.QDesktopServices.openUrl(QtCore.QUrl("t"))
+# QtGui.QDesktopServices.openUrl(QtCore.QUrl("t"))
# code ***********************************************************************************
-#form = RotateXYZGuiClass()
+# form = RotateXYZGuiClass()
-#def singleInstance():
+# def singleInstance():
# app = QtGui.qApp
#
# for i in app.topLevelWidgets():
@@ -14114,7 +15220,7 @@ def addObject(shape,name="Shape",layer=None):
# else:
# pass
#
-#singleInstance()
+# singleInstance()
###############################################################################################################
@@ -14123,15 +15229,13 @@ def addObject(shape,name="Shape",layer=None):
# def link(self, linkStr):
# QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr))
-class Ui_DockWidget(object):
+
+class Ui_DockWidget:
def link(self, linkStr):
- #QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr))
- try:
- QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr)) #workaround Qt5 waiting for PySide
- except:
- #QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr.fromLocalFile()))
- pass
-#class Ui_DockWidget(object):
+ with contextlib.suppress(Exception):
+ QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr)) # workaround Qt5 waiting for PySide
+
+ # class Ui_DockWidget(object):
def setupUi(self, DockWidget):
DockWidget.setObjectName("DockWidget")
DockWidget.resize(169, 480)
@@ -14139,8 +15243,8 @@ def setupUi(self, DockWidget):
icon.addPixmap(QtGui.QPixmap("kicad-StepUp-icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
DockWidget.setWindowIcon(icon)
DockWidget.setLayoutDirection(QtCore.Qt.LeftToRight)
- DockWidget.setFeatures(QtGui.QDockWidget.DockWidgetFloatable|QtGui.QDockWidget.DockWidgetMovable)
- DockWidget.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea|QtCore.Qt.RightDockWidgetArea)
+ DockWidget.setFeatures(QtGui.QDockWidget.DockWidgetFloatable | QtGui.QDockWidget.DockWidgetMovable)
+ DockWidget.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea)
self.dockWidgetContents = QtGui.QWidget()
self.dockWidgetContents.setObjectName("dockWidgetContents")
self.horizontalLayoutWidget = QtGui.QWidget(self.dockWidgetContents)
@@ -14152,7 +15256,7 @@ def setupUi(self, DockWidget):
self.horizontalLayout.setObjectName("horizontalLayout")
self.dock_left = QtGui.QPushButton(self.horizontalLayoutWidget)
self.dock_left.setMaximumSize(QtCore.QSize(28, 28))
- self.dock_left.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.dock_left.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.dock_left.setText("")
icon1 = QtGui.QIcon()
icon1.addPixmap(QtGui.QPixmap("icons-new/dock_left.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14162,7 +15266,7 @@ def setupUi(self, DockWidget):
self.horizontalLayout.addWidget(self.dock_left)
self.dock_float = QtGui.QPushButton(self.horizontalLayoutWidget)
self.dock_float.setMaximumSize(QtCore.QSize(28, 28))
- self.dock_float.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.dock_float.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.dock_float.setText("")
icon2 = QtGui.QIcon()
icon2.addPixmap(QtGui.QPixmap("icons-new/un_dock.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14172,7 +15276,7 @@ def setupUi(self, DockWidget):
self.horizontalLayout.addWidget(self.dock_float)
self.dock_minimize = QtGui.QPushButton(self.horizontalLayoutWidget)
self.dock_minimize.setMaximumSize(QtCore.QSize(28, 28))
- self.dock_minimize.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.dock_minimize.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.dock_minimize.setText("")
icon3 = QtGui.QIcon()
icon3.addPixmap(QtGui.QPixmap("icons-new/minimize.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14182,7 +15286,7 @@ def setupUi(self, DockWidget):
self.horizontalLayout.addWidget(self.dock_minimize)
self.dock_right = QtGui.QPushButton(self.horizontalLayoutWidget)
self.dock_right.setMaximumSize(QtCore.QSize(28, 28))
- self.dock_right.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.dock_right.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.dock_right.setText("")
icon4 = QtGui.QIcon()
icon4.addPixmap(QtGui.QPixmap("icons-new/dock_right.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14192,7 +15296,7 @@ def setupUi(self, DockWidget):
self.horizontalLayout.addWidget(self.dock_right)
self.close = QtGui.QPushButton(self.horizontalLayoutWidget)
self.close.setMaximumSize(QtCore.QSize(28, 28))
- self.close.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.close.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.close.setText("")
icon5 = QtGui.QIcon()
icon5.addPixmap(QtGui.QPixmap("icons-new/closeW.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14237,7 +15341,7 @@ def setupUi(self, DockWidget):
self.TranslateX = QtGui.QPushButton(self.gridLayoutWidget_4)
self.TranslateX.setMinimumSize(QtCore.QSize(32, 32))
self.TranslateX.setMaximumSize(QtCore.QSize(64, 64))
- self.TranslateX.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.TranslateX.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.TranslateX.setText("")
icon6 = QtGui.QIcon()
icon6.addPixmap(QtGui.QPixmap("icons-new/shiftX.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14247,7 +15351,7 @@ def setupUi(self, DockWidget):
self.TranslateY = QtGui.QPushButton(self.gridLayoutWidget_4)
self.TranslateY.setMinimumSize(QtCore.QSize(32, 32))
self.TranslateY.setMaximumSize(QtCore.QSize(64, 64))
- self.TranslateY.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.TranslateY.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.TranslateY.setText("")
icon7 = QtGui.QIcon()
icon7.addPixmap(QtGui.QPixmap("icons-new/shiftY.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14257,7 +15361,7 @@ def setupUi(self, DockWidget):
self.TranslateZ = QtGui.QPushButton(self.gridLayoutWidget_4)
self.TranslateZ.setMinimumSize(QtCore.QSize(32, 32))
self.TranslateZ.setMaximumSize(QtCore.QSize(64, 64))
- self.TranslateZ.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.TranslateZ.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.TranslateZ.setText("")
icon8 = QtGui.QIcon()
icon8.addPixmap(QtGui.QPixmap("icons-new/shiftZ.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14267,7 +15371,7 @@ def setupUi(self, DockWidget):
self.PutOnX = QtGui.QPushButton(self.gridLayoutWidget_4)
self.PutOnX.setMinimumSize(QtCore.QSize(32, 32))
self.PutOnX.setMaximumSize(QtCore.QSize(64, 64))
- self.PutOnX.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.PutOnX.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.PutOnX.setText("")
icon9 = QtGui.QIcon()
icon9.addPixmap(QtGui.QPixmap("icons-new/putX.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14277,7 +15381,7 @@ def setupUi(self, DockWidget):
self.PutOnY = QtGui.QPushButton(self.gridLayoutWidget_4)
self.PutOnY.setMinimumSize(QtCore.QSize(32, 32))
self.PutOnY.setMaximumSize(QtCore.QSize(64, 64))
- self.PutOnY.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.PutOnY.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.PutOnY.setText("")
icon10 = QtGui.QIcon()
icon10.addPixmap(QtGui.QPixmap("icons-new/putY.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14287,7 +15391,7 @@ def setupUi(self, DockWidget):
self.PutOnZ = QtGui.QPushButton(self.gridLayoutWidget_4)
self.PutOnZ.setMinimumSize(QtCore.QSize(32, 32))
self.PutOnZ.setMaximumSize(QtCore.QSize(64, 64))
- self.PutOnZ.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.PutOnZ.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.PutOnZ.setText("")
icon11 = QtGui.QIcon()
icon11.addPixmap(QtGui.QPixmap("icons-new/putZ.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14326,7 +15430,7 @@ def setupUi(self, DockWidget):
self.RotateX = QtGui.QPushButton(self.gridLayoutWidget_5)
self.RotateX.setMinimumSize(QtCore.QSize(32, 32))
self.RotateX.setMaximumSize(QtCore.QSize(64, 64))
- self.RotateX.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.RotateX.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.RotateX.setText("")
icon12 = QtGui.QIcon()
icon12.addPixmap(QtGui.QPixmap("icons-new/rotateX.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14336,7 +15440,7 @@ def setupUi(self, DockWidget):
self.RotateY = QtGui.QPushButton(self.gridLayoutWidget_5)
self.RotateY.setMinimumSize(QtCore.QSize(32, 32))
self.RotateY.setMaximumSize(QtCore.QSize(64, 64))
- self.RotateY.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.RotateY.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.RotateY.setText("")
icon13 = QtGui.QIcon()
icon13.addPixmap(QtGui.QPixmap("icons-new/rotateY.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14346,7 +15450,7 @@ def setupUi(self, DockWidget):
self.RotateZ = QtGui.QPushButton(self.gridLayoutWidget_5)
self.RotateZ.setMinimumSize(QtCore.QSize(32, 32))
self.RotateZ.setMaximumSize(QtCore.QSize(64, 64))
- self.RotateZ.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.RotateZ.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.RotateZ.setText("")
icon14 = QtGui.QIcon()
icon14.addPixmap(QtGui.QPixmap("icons-new/rotateZ.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14356,7 +15460,7 @@ def setupUi(self, DockWidget):
self.CenterX = QtGui.QPushButton(self.gridLayoutWidget_5)
self.CenterX.setMinimumSize(QtCore.QSize(32, 32))
self.CenterX.setMaximumSize(QtCore.QSize(64, 64))
- self.CenterX.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.CenterX.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.CenterX.setText("")
icon15 = QtGui.QIcon()
icon15.addPixmap(QtGui.QPixmap("icons-new/centerX.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14366,7 +15470,7 @@ def setupUi(self, DockWidget):
self.CenterY = QtGui.QPushButton(self.gridLayoutWidget_5)
self.CenterY.setMinimumSize(QtCore.QSize(32, 32))
self.CenterY.setMaximumSize(QtCore.QSize(64, 64))
- self.CenterY.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.CenterY.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.CenterY.setText("")
icon16 = QtGui.QIcon()
icon16.addPixmap(QtGui.QPixmap("icons-new/centerY.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14376,7 +15480,7 @@ def setupUi(self, DockWidget):
self.CenterZ = QtGui.QPushButton(self.gridLayoutWidget_5)
self.CenterZ.setMinimumSize(QtCore.QSize(32, 32))
self.CenterZ.setMaximumSize(QtCore.QSize(64, 64))
- self.CenterZ.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.CenterZ.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.CenterZ.setText("")
icon17 = QtGui.QIcon()
icon17.addPixmap(QtGui.QPixmap("icons-new/centerZ.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14393,7 +15497,7 @@ def setupUi(self, DockWidget):
self.HelpPB = QtGui.QPushButton(self.gridLayoutWidget_6)
self.HelpPB.setMinimumSize(QtCore.QSize(27, 36))
self.HelpPB.setMaximumSize(QtCore.QSize(64, 64))
- self.HelpPB.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.HelpPB.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.HelpPB.setText("")
icon18 = QtGui.QIcon()
icon18.addPixmap(QtGui.QPixmap("icons-new/help.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14403,7 +15507,7 @@ def setupUi(self, DockWidget):
self.ConfigPB = QtGui.QPushButton(self.gridLayoutWidget_6)
self.ConfigPB.setMinimumSize(QtCore.QSize(60, 36))
self.ConfigPB.setMaximumSize(QtCore.QSize(64, 64))
- self.ConfigPB.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.ConfigPB.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.ConfigPB.setText("")
icon19 = QtGui.QIcon()
icon19.addPixmap(QtGui.QPixmap("icons-new/edit.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14413,7 +15517,7 @@ def setupUi(self, DockWidget):
self.pushPCB = QtGui.QPushButton(self.gridLayoutWidget_6)
self.pushPCB.setMinimumSize(QtCore.QSize(47, 36))
self.pushPCB.setMaximumSize(QtCore.QSize(64, 64))
- self.pushPCB.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.pushPCB.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.pushPCB.setText("")
icon20 = QtGui.QIcon()
icon20.addPixmap(QtGui.QPixmap("icons-new/Sketcher_Rectangle.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14423,7 +15527,7 @@ def setupUi(self, DockWidget):
self.makeCompound = QtGui.QPushButton(self.gridLayoutWidget_6)
self.makeCompound.setMinimumSize(QtCore.QSize(47, 36))
self.makeCompound.setMaximumSize(QtCore.QSize(64, 64))
- self.makeCompound.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.makeCompound.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.makeCompound.setText("")
icon21 = QtGui.QIcon()
icon21.addPixmap(QtGui.QPixmap("icons-new/compound.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14433,7 +15537,7 @@ def setupUi(self, DockWidget):
self.LoadBoard = QtGui.QPushButton(self.gridLayoutWidget_6)
self.LoadBoard.setMinimumSize(QtCore.QSize(60, 36))
self.LoadBoard.setMaximumSize(QtCore.QSize(64, 64))
- self.LoadBoard.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.LoadBoard.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.LoadBoard.setText("")
icon22 = QtGui.QIcon()
icon22.addPixmap(QtGui.QPixmap("icons-new/importBoard.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14443,7 +15547,7 @@ def setupUi(self, DockWidget):
self.ScaleVRML = QtGui.QPushButton(self.gridLayoutWidget_6)
self.ScaleVRML.setMinimumSize(QtCore.QSize(60, 36))
self.ScaleVRML.setMaximumSize(QtCore.QSize(64, 64))
- self.ScaleVRML.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.ScaleVRML.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.ScaleVRML.setText("")
icon23 = QtGui.QIcon()
icon23.addPixmap(QtGui.QPixmap("icons-new/export3DModel.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14471,7 +15575,7 @@ def setupUi(self, DockWidget):
self.LoadFootprint = QtGui.QPushButton(self.gridLayoutWidget_6)
self.LoadFootprint.setMinimumSize(QtCore.QSize(60, 36))
self.LoadFootprint.setMaximumSize(QtCore.QSize(64, 64))
- self.LoadFootprint.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.LoadFootprint.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.LoadFootprint.setText("")
icon26 = QtGui.QIcon()
icon26.addPixmap(QtGui.QPixmap("icons-new/importFP.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14490,7 +15594,7 @@ def setupUi(self, DockWidget):
self.makeUnion = QtGui.QPushButton(self.gridLayoutWidget_6)
self.makeUnion.setMinimumSize(QtCore.QSize(27, 36))
self.makeUnion.setMaximumSize(QtCore.QSize(64, 64))
- self.makeUnion.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.makeUnion.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.makeUnion.setText("")
icon28 = QtGui.QIcon()
icon28.addPixmap(QtGui.QPixmap("icons-new/fusion.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14500,7 +15604,7 @@ def setupUi(self, DockWidget):
self.import3D = QtGui.QPushButton(self.gridLayoutWidget_6)
self.import3D.setMinimumSize(QtCore.QSize(27, 36))
self.import3D.setMaximumSize(QtCore.QSize(64, 64))
- self.import3D.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.import3D.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.import3D.setText("")
icon29 = QtGui.QIcon()
icon29.addPixmap(QtGui.QPixmap("icons-new/add_block.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14510,7 +15614,7 @@ def setupUi(self, DockWidget):
self.checkCollisions = QtGui.QPushButton(self.gridLayoutWidget_6)
self.checkCollisions.setMinimumSize(QtCore.QSize(27, 36))
self.checkCollisions.setMaximumSize(QtCore.QSize(64, 64))
- self.checkCollisions.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.checkCollisions.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.checkCollisions.setText("")
icon30 = QtGui.QIcon()
icon30.addPixmap(QtGui.QPixmap("icons-new/collisions.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14520,7 +15624,7 @@ def setupUi(self, DockWidget):
self.export3DStep = QtGui.QPushButton(self.gridLayoutWidget_6)
self.export3DStep.setMinimumSize(QtCore.QSize(60, 36))
self.export3DStep.setMaximumSize(QtCore.QSize(64, 64))
- self.export3DStep.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.export3DStep.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.export3DStep.setText("")
icon31 = QtGui.QIcon()
icon31.addPixmap(QtGui.QPixmap("icons-new/export3DStep.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14530,7 +15634,7 @@ def setupUi(self, DockWidget):
self.CreateAxis = QtGui.QPushButton(self.gridLayoutWidget_6)
self.CreateAxis.setMinimumSize(QtCore.QSize(27, 36))
self.CreateAxis.setMaximumSize(QtCore.QSize(64, 64))
- self.CreateAxis.setStyleSheet(u"min-width: 20px;min-height: 20px; ")
+ self.CreateAxis.setStyleSheet("min-width: 20px;min-height: 20px; ")
self.CreateAxis.setText("")
icon32 = QtGui.QIcon()
icon32.addPixmap(QtGui.QPixmap("icons-new/axis.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
@@ -14546,205 +15650,204 @@ def setupUi(self, DockWidget):
self.textEdit.setObjectName("textEdit")
DockWidget.setWidget(self.dockWidgetContents)
-
-###############################################################################################################
+ ###############################################################################################################
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(axis_b64))
self.CreateAxis.setIcon(QtGui.QIcon(pm))
- self.CreateAxis.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))
+ self.CreateAxis.setIconSize(QtCore.QSize(btn_md_sizeX, btn_md_sizeY))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(exportPart_b64))
self.cb_expStep.setIcon(QtGui.QIcon(pm))
- self.cb_expStep.setIconSize(QtCore.QSize(chkb_sizeX,chkb_sizeY))
+ self.cb_expStep.setIconSize(QtCore.QSize(chkb_sizeX, chkb_sizeY))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(virtual_b64))
self.cb_virtual.setIcon(QtGui.QIcon(pm))
- self.cb_virtual.setIconSize(QtCore.QSize(chkb_sizeX,chkb_sizeY))
+ self.cb_virtual.setIconSize(QtCore.QSize(chkb_sizeX, chkb_sizeY))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(materials_b64))
self.cb_materials.setIcon(QtGui.QIcon(pm))
- self.cb_materials.setIconSize(QtCore.QSize(chkb_sizeX,chkb_sizeY))
+ self.cb_materials.setIconSize(QtCore.QSize(chkb_sizeX, chkb_sizeY))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(collisions_b64))
self.checkCollisions.setIcon(QtGui.QIcon(pm))
- self.checkCollisions.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))
+ self.checkCollisions.setIconSize(QtCore.QSize(btn_md_sizeX, btn_md_sizeY))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(importBoard_b64))
- self.LoadBoard.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.LoadBoard.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.LoadBoard.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(export3DModel_b64))
- self.ScaleVRML.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.ScaleVRML.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.ScaleVRML.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(importFP_b64))
- self.LoadFootprint.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.LoadFootprint.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.LoadFootprint.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(compound_b64))
- self.makeCompound.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.makeCompound.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.makeCompound.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(fusion_b64))
- self.makeUnion.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.makeUnion.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.makeUnion.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(rotateX_b64))
- self.RotateX.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.RotateX.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.RotateX.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(rotateY_b64))
- self.RotateY.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.RotateY.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.RotateY.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(rotateZ_b64))
- self.RotateZ.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.RotateZ.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.RotateZ.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(shiftX_b64))
- self.TranslateX.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.TranslateX.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.TranslateX.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(shiftY_b64))
- self.TranslateY.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.TranslateY.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.TranslateY.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(shiftZ_b64))
- self.TranslateZ.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.TranslateZ.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.TranslateZ.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(centerX_b64))
- self.CenterX.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.CenterX.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.CenterX.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(centerY_b64))
- self.CenterY.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.CenterY.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.CenterY.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(centerZ_b64))
- self.CenterZ.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.CenterZ.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.CenterZ.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(putX_b64))
- self.PutOnX.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.PutOnX.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.PutOnX.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(putY_b64))
- self.PutOnY.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.PutOnY.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.PutOnY.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(putZ_b64))
- self.PutOnZ.setIconSize(QtCore.QSize(btn_sizeX,btn_sizeY))
+ self.PutOnZ.setIconSize(QtCore.QSize(btn_sizeX, btn_sizeY))
self.PutOnZ.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(edit_b64))
- self.ConfigPB.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))
+ self.ConfigPB.setIconSize(QtCore.QSize(btn_md_sizeX, btn_md_sizeY))
self.ConfigPB.setIcon(QtGui.QIcon(pm))
-
+
pm = QtGui.QPixmap()
- pm.loadFromData(base64.b64decode(pcb_edge_b64)) #sketch
- self.pushPCB.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))
+ pm.loadFromData(base64.b64decode(pcb_edge_b64)) # sketch
+ self.pushPCB.setIconSize(QtCore.QSize(btn_md_sizeX, btn_md_sizeY))
self.pushPCB.setIcon(QtGui.QIcon(pm))
-
+
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(help_b64))
- self.HelpPB.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))
+ self.HelpPB.setIconSize(QtCore.QSize(btn_md_sizeX, btn_md_sizeY))
self.HelpPB.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(add_block_b64))
- self.import3D.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))
+ self.import3D.setIconSize(QtCore.QSize(btn_md_sizeX, btn_md_sizeY))
self.import3D.setIcon(QtGui.QIcon(pm))
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(stop_grey_b64))
- #self.collisionLbl.setPixmap(pm)
+ # self.collisionLbl.setPixmap(pm)
##self.collisionLbl.setPixmapSize(QtCore.QSize(btn_sm_sizeX,btn_sm_sizeY)) ## todo
- #self.checkCollisions.clicked.connect(changePixmap_stop)
- #self.checkCollisions.clicked.connect(changePixmap_ok)
+ # self.checkCollisions.clicked.connect(changePixmap_stop)
+ # self.checkCollisions.clicked.connect(changePixmap_ok)
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(dock_left_b64))
- self.dock_left.setIconSize(QtCore.QSize(btn_sm_sizeX,btn_sm_sizeY))
+ self.dock_left.setIconSize(QtCore.QSize(btn_sm_sizeX, btn_sm_sizeY))
self.dock_left.setIcon(QtGui.QIcon(pm))
self.dock_left.clicked.connect(dock)
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(un_dock_b64))
- self.dock_float.setIconSize(QtCore.QSize(btn_sm_sizeX,btn_sm_sizeY))
+ self.dock_float.setIconSize(QtCore.QSize(btn_sm_sizeX, btn_sm_sizeY))
self.dock_float.setIcon(QtGui.QIcon(pm))
self.dock_float.clicked.connect(undock)
- #self.dock_minimize.clicked.connect(minimz_alt)
+ # self.dock_minimize.clicked.connect(minimz_alt)
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(minimize_b64))
- self.dock_minimize.setIconSize(QtCore.QSize(btn_sm_sizeX,btn_sm_sizeY))
+ self.dock_minimize.setIconSize(QtCore.QSize(btn_sm_sizeX, btn_sm_sizeY))
self.dock_minimize.setIcon(QtGui.QIcon(pm))
self.dock_minimize.clicked.connect(minimz)
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(dock_right_b64))
- self.dock_right.setIconSize(QtCore.QSize(btn_sm_sizeX,btn_sm_sizeY))
+ self.dock_right.setIconSize(QtCore.QSize(btn_sm_sizeX, btn_sm_sizeY))
self.dock_right.setIcon(QtGui.QIcon(pm))
self.dock_right.clicked.connect(dock_right)
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(closeW_b64))
- self.close.setIconSize(QtCore.QSize(btn_sm_sizeX,btn_sm_sizeY))
+ self.close.setIconSize(QtCore.QSize(btn_sm_sizeX, btn_sm_sizeY))
self.close.setIcon(QtGui.QIcon(pm))
self.close.clicked.connect(close_ksu)
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(export3DStep_b64))
- self.export3DStep.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))
+ self.export3DStep.setIconSize(QtCore.QSize(btn_md_sizeX, btn_md_sizeY))
self.export3DStep.setIcon(QtGui.QIcon(pm))
self.export3DStep.clicked.connect(self.onExport3DStep)
- self.RotateX.clicked.connect(self.onRotateX)
+ self.RotateX.clicked.connect(self.onRotateX)
self.RotateY.clicked.connect(self.onRotateY)
self.RotateZ.clicked.connect(self.onRotateZ)
- self.TranslateX.clicked.connect(self.onTranslateX)
+ self.TranslateX.clicked.connect(self.onTranslateX)
self.TranslateY.clicked.connect(self.onTranslateY)
self.TranslateZ.clicked.connect(self.onTranslateZ)
- self.CenterX.clicked.connect(self.onCenterX)
+ self.CenterX.clicked.connect(self.onCenterX)
self.CenterY.clicked.connect(self.onCenterY)
self.CenterZ.clicked.connect(self.onCenterZ)
- self.PutOnX.clicked.connect(self.onPutOnX)
+ self.PutOnX.clicked.connect(self.onPutOnX)
self.PutOnY.clicked.connect(self.onPutOnY)
self.PutOnZ.clicked.connect(self.onPutOnZ)
self.CreateAxis.clicked.connect(self.onCreateAxis)
- self.LoadFootprint.clicked.connect(self.onLoadFootprint_click)
- if enable_materials==0:
- #export_board_2step=False
+ self.LoadFootprint.clicked.connect(self.onLoadFootprint_click)
+ if enable_materials == 0:
+ # export_board_2step=False
self.cb_materials.setChecked(False) # Check by default True or False
else:
self.cb_materials.setChecked(True) # Check by default True or False
# if enable_materials:
# self.checkBox_4.setChecked(True) # Check by default True or False
- if export_board_2step==False:
- #export_board_2step=False
+ if not export_board_2step:
+ # export_board_2step=False
self.cb_expStep.setChecked(False) # Check by default True or False
else:
self.cb_expStep.setChecked(True) # Check by default True or False
- say("export to STEP "+str(export_board_2step))
- if addVirtual==0:
- #export_board_2step=False
+ say("export to STEP " + str(export_board_2step))
+ if addVirtual == 0:
+ # export_board_2step=False
self.cb_virtual.setChecked(False) # Check by default True or False
else:
self.cb_virtual.setChecked(True) # Check by default True or False
##export_board_2step=True
self.cb_virtual.clicked.connect(self.on_cb_virtual_clicked) # connect on def "on_checkBox_1_clicked"
self.cb_materials.clicked.connect(self.on_cb_materials_clicked) # connect on def "on_cb_materials_clicked"
- self.ScaleVRML.clicked.connect(self.onScaleVRML)
+ self.ScaleVRML.clicked.connect(self.onScaleVRML)
self.checkCollisions.clicked.connect(self.onCollisions)
self.import3D.clicked.connect(self.onImport3DModel)
self.LoadBoard.clicked.connect(self.onLoadBoard_click)
self.cb_expStep.clicked.connect(self.on_cb_expStep_clicked)
home = expanduser("~")
- ini_file_full_path_bold=''+home+os.sep+'ksu-config.ini'
- ini_file_full_path=home+os.sep+'ksu-config.ini'
- #self.config_ini_Lbl = QtGui.QLabel(ini_file_full_path, self)
- #self.config_ini_Lbl.setText(ini_file_full_path_bold)
- self.ConfigPB.clicked.connect(self.onCfg)
+ ini_file_full_path_bold = "" + home + os.sep + "ksu-config.ini"
+ ini_file_full_path = home + os.sep + "ksu-config.ini"
+ # self.config_ini_Lbl = QtGui.QLabel(ini_file_full_path, self)
+ # self.config_ini_Lbl.setText(ini_file_full_path_bold)
+ self.ConfigPB.clicked.connect(self.onCfg)
self.pushPCB.clicked.connect(self.onPushPCB)
self.HelpPB.clicked.connect(self.onHelp)
self.makeUnion.clicked.connect(group_part_union)
self.makeCompound.clicked.connect(group_part)
self.config_ini_Lbl.linkActivated.connect(self.link)
- local_link=""+ini_file_full_path_bold+""
- #self.config_ini_Lbl.setText(local_link)
- self.config_ini_Lbl.setText('')
+ "" + ini_file_full_path_bold + ""
+ # self.config_ini_Lbl.setText(local_link)
+ self.config_ini_Lbl.setText("")
self.config_ini_Lbl.setToolTip(translate("Ui_DockWidget", "ksu config ini file\nlocation"))
self.textInputRX.setAlignment(QtCore.Qt.AlignRight)
self.textInputRY.setAlignment(QtCore.Qt.AlignRight)
@@ -14752,8 +15855,8 @@ def setupUi(self, DockWidget):
self.textInputX.setAlignment(QtCore.Qt.AlignRight)
self.textInputY.setAlignment(QtCore.Qt.AlignRight)
self.textInputZ.setAlignment(QtCore.Qt.AlignRight)
-
-###############################################################################################################
+
+ ###############################################################################################################
self.retranslateUi(DockWidget)
QtCore.QMetaObject.connectSlotsByName(DockWidget)
@@ -14795,9 +15898,9 @@ def setupUi(self, DockWidget):
DockWidget.setTabOrder(self.ConfigPB, self.HelpPB)
DockWidget.setTabOrder(self.HelpPB, self.textEdit)
-## retraslateUi Qt5 compatibility #############################################################################################################
+ ## retraslateUi Qt5 compatibility #############################################################################################################
def retranslateUi(self, DockWidget):
- #DockWidget.setWindowTitle(QtGui.QApplication.translate("DockWidget", "kicad StepUp tools", None, QtGui.QApplication.UnicodeUTF8))
+ # DockWidget.setWindowTitle(QtGui.QApplication.translate("DockWidget", "kicad StepUp tools", None, QtGui.QApplication.UnicodeUTF8))
DockWidget.setWindowTitle(translate("Ui_DockWidget", "KiCad StepUp tools"))
self.dock_left.setToolTip(translate("Ui_DockWidget", "dock left"))
self.dock_float.setToolTip(translate("Ui_DockWidget", "un-dock (floating)"))
@@ -14829,411 +15932,428 @@ def retranslateUi(self, DockWidget):
self.CenterY.setToolTip(translate("Ui_DockWidget", "center Y"))
self.CenterZ.setToolTip(translate("Ui_DockWidget", "center Z"))
self.makeCompound.setToolTip(translate("Ui_DockWidget", "make Compound of Parts"))
- self.LoadBoard.setToolTip(translate("Ui_DockWidget", "Load KiCad\n"
-"Board .kicad_pcb"))
- self.ScaleVRML.setToolTip(translate("Ui_DockWidget", "export to KiCad:\n"
-"STEP & scaled VRML 1/2.54"))
- self.cb_virtual.setToolTip(translate("Ui_DockWidget", "enable loading\n"
-"virtual & mechanical\n"
-"models"))
- self.cb_materials.setToolTip(translate("Ui_DockWidget", "use wrl\n"
-"material"))
- self.LoadFootprint.setToolTip(translate("Ui_DockWidget", "load KiCad footprint\n"
-"\'kicad_mod\'"))
- self.cb_expStep.setToolTip(translate("Ui_DockWidget", "export STEP Board\n"
-"and Parts after loading"))
+ self.LoadBoard.setToolTip(translate("Ui_DockWidget", "Load KiCad\nBoard .kicad_pcb"))
+ self.ScaleVRML.setToolTip(translate("Ui_DockWidget", "export to KiCad:\nSTEP & scaled VRML 1/2.54"))
+ self.cb_virtual.setToolTip(translate("Ui_DockWidget", "enable loading\nvirtual & mechanical\nmodels"))
+ self.cb_materials.setToolTip(translate("Ui_DockWidget", "use wrl\nmaterial"))
+ self.LoadFootprint.setToolTip(translate("Ui_DockWidget", "load KiCad footprint\n'kicad_mod'"))
+ self.cb_expStep.setToolTip(translate("Ui_DockWidget", "export STEP Board\nand Parts after loading"))
self.makeUnion.setToolTip(translate("Ui_DockWidget", "make Union of Parts"))
- self.import3D.setToolTip(translate("Ui_DockWidget", "import STEP\n"
-"3D model"))
- self.checkCollisions.setToolTip(translate("Ui_DockWidget", "check Collisions\n"
-"tolerance 1e-06"))
+ self.import3D.setToolTip(translate("Ui_DockWidget", "import STEP\n3D model"))
+ self.checkCollisions.setToolTip(translate("Ui_DockWidget", "check Collisions\ntolerance 1e-06"))
self.export3DStep.setToolTip(translate("Ui_DockWidget", "export selected objects to STEP"))
self.CreateAxis.setToolTip(translate("Ui_DockWidget", "create reference Axis"))
self.HelpPB.setToolTip(translate("Ui_DockWidget", "Help & starting Guide"))
self.ConfigPB.setToolTip(translate("Ui_DockWidget", "view Config File content"))
- self.pushPCB.setToolTip(translate("Ui_DockWidget", "push PCB Edge to KiCad\n"
-"from Sketcher to pcbnew"))
- #self.config_ini_Lbl.setText("TextLabel"))
- #self.config_ini_Lbl.setText("TextLabel")
-
+ self.pushPCB.setToolTip(translate("Ui_DockWidget", "push PCB Edge to KiCad\nfrom Sketcher to pcbnew"))
+ # self.config_ini_Lbl.setText("TextLabel"))
+ # self.config_ini_Lbl.setText("TextLabel")
- ## NB!!! comment the line ##self.config_ini_Lbl.setText("TextLabel")
-###############################################################################################################
+ ## NB!!! comment the line ##self.config_ini_Lbl.setText("TextLabel")
+ ###############################################################################################################
def onRotateX(self):
FreeCAD.Console.PrintMessage("RotateX!")
- alpha=self.textInputRX.text()
- alpha=alpha.replace(',', '.')
- angle=alpha.split('.')
+ alpha = self.textInputRX.text()
+ alpha = alpha.replace(",", ".")
+ angle = alpha.split(".")
self.textInputRX.setText(angle[0])
- routineR_XYZ('x',angle[0])
- position=get_position()
-##
+ routineR_XYZ("x", angle[0])
+ get_position()
+
+ ##
def onRotateY(self):
FreeCAD.Console.PrintMessage("RotateY!")
- alpha=self.textInputRY.text()
- alpha=alpha.replace(',', '.')
- angle=alpha.split('.')
+ alpha = self.textInputRY.text()
+ alpha = alpha.replace(",", ".")
+ angle = alpha.split(".")
self.textInputRY.setText(angle[0])
- routineR_XYZ('y',angle[0])
- position=get_position()
-##
+ routineR_XYZ("y", angle[0])
+ get_position()
+
+ ##
def onRotateZ(self):
FreeCAD.Console.PrintMessage("RotateZ!")
- alpha=self.textInputRZ.text()
- alpha=alpha.replace(',', '.')
- angle=alpha.split('.')
+ alpha = self.textInputRZ.text()
+ alpha = alpha.replace(",", ".")
+ angle = alpha.split(".")
self.textInputRZ.setText(angle[0])
- routineR_XYZ('z',angle[0])
- position=get_position()
-##
+ routineR_XYZ("z", angle[0])
+ get_position()
+
+ ##
def onTranslateX(self):
- v=self.textInputX.text()
- v=v.replace(',', '.')
- v=v.replace(" ", "")
- #FreeCAD.Console.PrintMessage(v+"\r\n")
- routineT_XYZ('x',v)
- position=get_position()
-##
+ v = self.textInputX.text()
+ v = v.replace(",", ".")
+ v = v.replace(" ", "")
+ # FreeCAD.Console.PrintMessage(v+"\r\n")
+ routineT_XYZ("x", v)
+ get_position()
+
+ ##
def onTranslateY(self):
- v=self.textInputY.text()
- v=v.replace(',', '.')
- v=v.replace(" ", "")
- #FreeCAD.Console.PrintMessage(v+"\r\n")
- routineT_XYZ('y',v)
- position=get_position()
-##
+ v = self.textInputY.text()
+ v = v.replace(",", ".")
+ v = v.replace(" ", "")
+ # FreeCAD.Console.PrintMessage(v+"\r\n")
+ routineT_XYZ("y", v)
+ get_position()
+
+ ##
def onTranslateZ(self):
- v=self.textInputZ.text()
- v=v.replace(',', '.')
- v=v.replace(" ", "")
- #FreeCAD.Console.PrintMessage(v+"\r\n")
- routineT_XYZ('z',v)
- position=get_position()
-##
+ v = self.textInputZ.text()
+ v = v.replace(",", ".")
+ v = v.replace(" ", "")
+ # FreeCAD.Console.PrintMessage(v+"\r\n")
+ routineT_XYZ("z", v)
+ get_position()
+
+ ##
def onCenterX(self):
FreeCAD.Console.PrintMessage("centering\r\n")
- routineC_XYZ('x')
- position=get_position()
-##
+ routineC_XYZ("x")
+ get_position()
+
+ ##
def onCenterY(self):
FreeCAD.Console.PrintMessage("centering\r\n")
- routineC_XYZ('y')
- position=get_position()
-##
+ routineC_XYZ("y")
+ get_position()
+
+ ##
def onCenterZ(self):
FreeCAD.Console.PrintMessage("centering\r\n")
- routineC_XYZ('z')
- position=get_position()
-##
+ routineC_XYZ("z")
+ get_position()
+
+ ##
def onPutOnX(self):
FreeCAD.Console.PrintMessage("putting on Plane X\r\n")
- routineP_XYZ('x')
- position=get_position()
-##
+ routineP_XYZ("x")
+ get_position()
+
+ ##
def onPutOnY(self):
FreeCAD.Console.PrintMessage("putting on Plane Y\r\n")
- routineP_XYZ('y')
- position=get_position()
-##
+ routineP_XYZ("y")
+ get_position()
+
+ ##
def onPutOnZ(self):
FreeCAD.Console.PrintMessage("putting on Plane Z\r\n")
- routineP_XYZ('z')
- position=get_position()
-##
+ routineP_XYZ("z")
+ get_position()
+
+ ##
def onCreateAxis(self):
- FreeCAD.Console.PrintMessage("Create Axis!"+"\r\n")
+ FreeCAD.Console.PrintMessage("Create Axis!" + "\r\n")
if FreeCAD.ActiveDocument is None:
- #say("none")
+ # say("none")
FreeCAD.newDocument()
if FreeCAD.ActiveDocument.getObject("axis") is None:
create_axis()
-##
+
+ ##
def onLoadFootprint_click(self):
- #self.setGeometry(25, 250, 500, 500)
- sayw("kicad StepUp version "+str(___ver___))
- #say("tolerance on vertex = "+str(edge_tolerance))
+ # self.setGeometry(25, 250, 500, 500)
+ sayw("kicad StepUp version " + str(___ver___))
+ # say("tolerance on vertex = "+str(edge_tolerance))
say("tolerance on vertex applied")
import fps
+
fps.addfootprint()
# onLoadFootprint()
-##
+
+ ##
def on_cb_materials_clicked(self):
global enable_materials
if self.cb_materials.isChecked():
- enable_materials=1
- ini_vars[13] = u'enablematerials'
- #cfgParsWrite(configFilePath)
- #cfg_update_all()
+ enable_materials = 1
+ ini_vars[13] = "enablematerials"
+ # cfgParsWrite(configFilePath)
+ # cfg_update_all()
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- prefs.SetBool('vrml_materials',1)
+ prefs.SetBool("vrml_materials", 1)
else:
- enable_materials=0
- ini_vars[13] = u'nomaterials'
- #cfgParsWrite(configFilePath)
- #cfg_update_all()
+ enable_materials = 0
+ ini_vars[13] = "nomaterials"
+ # cfgParsWrite(configFilePath)
+ # cfg_update_all()
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- prefs.SetBool('vrml_materials',0)
- say("materials = "+str(enable_materials))
-##
+ prefs.SetBool("vrml_materials", 0)
+ say("materials = " + str(enable_materials))
+
+ ##
def onScaleVRML(self):
global applymaterials, exportS
- FreeCAD.Console.PrintMessage("ScaleToVRML!"+"\r\n")
- applymaterials=0
+ FreeCAD.Console.PrintMessage("ScaleToVRML!" + "\r\n")
+ applymaterials = 0
if self.cb_materials.isChecked():
- applymaterials=1
- #self.setGeometry(25, 250, 500, 500)
- result=routineScaleVRML()
- #position=get_position()
- #try:
+ applymaterials = 1
+ # self.setGeometry(25, 250, 500, 500)
+ result = routineScaleVRML()
+ # position=get_position()
+ # try:
# dummy=str(position[0])
##if exportS:
## try:
## say("X:"+str(position[0]))
## say("Y:"+str(position[1]))
## say("Z:"+str(position[2]))
- #except:
+ # except:
# pass
- if result==-1:
- msg="************\r\nSelect an object\r\n************"
+ if result == -1:
+ msg = "************\r\nSelect an object\r\n************"
self.labelInfoMsg.setText(msg)
-##
+
+ ##
def changePixmap_stop_disabled(self):
- #print("Do stuff here")
+ # print("Do stuff here")
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(stop_b64))
self.collisionLbl.setPixmap(pm)
self.collisionLbl.setEnabled(False)
- self.collisionLbl.setToolTip(translate("Ui_DockWidget", 'collisions result status'))
- #self.setPixmap(pm)
- #self.pixmap = QtGui.QPixmap(pm)
- #self.repaint() # repaint() will trigger the paintEvent(self, event), this way the new pixmap will be drawn on the label
+ self.collisionLbl.setToolTip(translate("Ui_DockWidget", "collisions result status"))
+ # self.setPixmap(pm)
+ # self.pixmap = QtGui.QPixmap(pm)
+ # self.repaint() # repaint() will trigger the paintEvent(self, event), this way the new pixmap will be drawn on the label
+
##self.checkCollisions.clicked.connect(changePixmap_ok)
-##
+ ##
def changePixmap_ok(self):
- #print("Do stuff here")
+ # print("Do stuff here")
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(ok_b64))
- #self.collisionLbl.setPixmap(pm)
- #self.collisionLbl.setEnabled(True)
- self.checkCollisions.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))
+ # self.collisionLbl.setPixmap(pm)
+ # self.collisionLbl.setEnabled(True)
+ self.checkCollisions.setIconSize(QtCore.QSize(btn_md_sizeX, btn_md_sizeY))
self.checkCollisions.setIcon(pm)
- #self.checkCollisions.setEnabled(True)
+ # self.checkCollisions.setEnabled(True)
QtCore.QTimer.singleShot(timer_Collisions, self.changePixmap_button_base)
- self.checkCollisions.setToolTip(translate("Ui_DockWidget", 'NO collisions found'))
- #self.setPixmap(pm)
+ self.checkCollisions.setToolTip(translate("Ui_DockWidget", "NO collisions found"))
+ # self.setPixmap(pm)
##self.pixmap = QtGui.QPixmap(pm)
- #self.repaint() # repaint() will trigger the paintEvent(self, event), this way the new pixmap will be drawn on the label
-##
+ # self.repaint() # repaint() will trigger the paintEvent(self, event), this way the new pixmap will be drawn on the label
+
+ ##
def changePixmap_button_base(self):
- #print("Do stuff here")
+ # print("Do stuff here")
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(collisions_b64))
- #self.collisionLbl.setPixmap(pm)
- #self.collisionLbl.setEnabled(True)
- self.checkCollisions.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))
+ # self.collisionLbl.setPixmap(pm)
+ # self.collisionLbl.setEnabled(True)
+ self.checkCollisions.setIconSize(QtCore.QSize(btn_md_sizeX, btn_md_sizeY))
self.checkCollisions.setIcon(pm)
- #self.checkCollisions.setEnabled(True)
- #QtCore.QTimer.singleShot(timer_Collisions, self.changePixmap_stop_disabled)
- self.checkCollisions.setToolTip(translate("Ui_DockWidget", 'check Collisions\ntolerance 1e-06'))
- #self.setPixmap(pm)
+ # self.checkCollisions.setEnabled(True)
+ # QtCore.QTimer.singleShot(timer_Collisions, self.changePixmap_stop_disabled)
+ self.checkCollisions.setToolTip(translate("Ui_DockWidget", "check Collisions\ntolerance 1e-06"))
+ # self.setPixmap(pm)
##self.pixmap = QtGui.QPixmap(pm)
- #self.repaint() # repaint() will trigger the paintEvent(self, event), this way the new pixmap will be drawn on the label
-##
+ # self.repaint() # repaint() will trigger the paintEvent(self, event), this way the new pixmap will be drawn on the label
+
+ ##
def changePixmap_collisions(self):
- #print("Do stuff here")
+ # print("Do stuff here")
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(stop_b64))
- self.checkCollisions.setIconSize(QtCore.QSize(btn_md_sizeX,btn_md_sizeY))
+ self.checkCollisions.setIconSize(QtCore.QSize(btn_md_sizeX, btn_md_sizeY))
self.checkCollisions.setIcon(pm)
QtCore.QTimer.singleShot(timer_Collisions, self.changePixmap_button_base)
- self.checkCollisions.setToolTip(translate("Ui_DockWidget", 'collisions FOUND!'))
- #self.setPixmap(pm)
- #self.pixmap = QtGui.QPixmap(pm)
- #self.repaint() # repaint() will trigger the paintEvent(self, event), this way the new pixmap will be drawn on the label
-##
+ self.checkCollisions.setToolTip(translate("Ui_DockWidget", "collisions FOUND!"))
+ # self.setPixmap(pm)
+ # self.pixmap = QtGui.QPixmap(pm)
+ # self.repaint() # repaint() will trigger the paintEvent(self, event), this way the new pixmap will be drawn on the label
+
+ ##
def changePixmap_stop(self):
- #print("Do stuff here")
+ # print("Do stuff here")
pm = QtGui.QPixmap()
pm.loadFromData(base64.b64decode(stop_b64))
self.collisionLbl.setPixmap(pm)
self.collisionLbl.setEnabled(True)
QtCore.QTimer.singleShot(timer_Collisions, self.changePixmap_stop_disabled)
- self.collisionLbl.setToolTip(translate("Ui_DockWidget", 'collisions FOUND!'))
- #self.setPixmap(pm)
- #self.pixmap = QtGui.QPixmap(pm)
- #self.repaint() # repaint() will trigger the paintEvent(self, event), this way the new pixmap will be drawn on the label
-##
+ self.collisionLbl.setToolTip(translate("Ui_DockWidget", "collisions FOUND!"))
+ # self.setPixmap(pm)
+ # self.pixmap = QtGui.QPixmap(pm)
+ # self.repaint() # repaint() will trigger the paintEvent(self, event), this way the new pixmap will be drawn on the label
+
+ ##
def onImport3DModel(self):
-
+
Import3DModelF()
-##
+
+ ##
def onExport3DStep(self):
Export3DStepF()
-
-##
+
+ ##
def onCollisions(self):
- #self.setGeometry(25, 250, 500, 500)
- collisions=routineCollisions()
- if collisions==0:
+ # self.setGeometry(25, 250, 500, 500)
+ collisions = routineCollisions()
+ if collisions == 0:
self.changePixmap_ok()
- elif collisions==1:
+ elif collisions == 1:
self.changePixmap_collisions()
else:
self.changePixmap_button_base()
# self.label17.setText("No")
# self.label18.setText("collisions")
# self.label19.setText("found!")
- #elif collisions==1:
+ # elif collisions==1:
# self.label17.setText("Collisions")
# self.label18.setText("detected!")
# self.label19.setText("!!!")
- #else:
+ # else:
# self.label17.setText(" ")
# self.label18.setText(" ")
# self.label19.setText(" ")
+
def onLoadBoard_click(self):
- #self.setGeometry(25, 250, 500, 500)
- sayw("kicad StepUp version "+str(___ver___))
- #say("tolerance on vertex = "+str(edge_tolerance))
+ # self.setGeometry(25, 250, 500, 500)
+ sayw("kicad StepUp version " + str(___ver___))
+ # say("tolerance on vertex = "+str(edge_tolerance))
say("tolerance on vertex applied")
- #ini_content=read_ini_file()
- ini_content=cfg_read_all()
+ # ini_content=read_ini_file()
+ ini_content = cfg_read_all()
self.textEdit.setText(ini_content)
cfg_read_all()
- #cfgParsRead(configFilePath)
+ # cfgParsRead(configFilePath)
onLoadBoard()
-##
+
+ ##
def on_cb_expStep_clicked(self):
global export_board_2step
if self.cb_expStep.isChecked():
- export_board_2step=True
- ini_vars[12] = u'yes'
- #cfgParsWrite(configFilePath)
- #cfg_update_all()
+ export_board_2step = True
+ ini_vars[12] = "yes"
+ # cfgParsWrite(configFilePath)
+ # cfg_update_all()
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- prefs.SetBool('exp_step',1)
+ prefs.SetBool("exp_step", 1)
else:
- export_board_2step=False
- ini_vars[12] = u'no'
- #cfgParsWrite(configFilePath)
- #cfg_update_all()
+ export_board_2step = False
+ ini_vars[12] = "no"
+ # cfgParsWrite(configFilePath)
+ # cfg_update_all()
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- prefs.SetBool('exp_step',0)
- say("export STEP = "+str(export_board_2step))
-##
+ prefs.SetBool("exp_step", 0)
+ say("export STEP = " + str(export_board_2step))
+
+ ##
def on_cb_virtual_clicked(self):
global addVirtual
if self.cb_virtual.isChecked():
- addVirtual=1
- ini_vars[7] = u'addVirtual'
- #cfgParsWrite(configFilePath)
- #cfg_update_all()
+ addVirtual = 1
+ ini_vars[7] = "addVirtual"
+ # cfgParsWrite(configFilePath)
+ # cfg_update_all()
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- prefs.SetBool('mode_virtual',1)
+ prefs.SetBool("mode_virtual", 1)
else:
- addVirtual=0
- ini_vars[7] = u'noVirtual'
- #cfgParsWrite(configFilePath)
- #cfg_update_all()
+ addVirtual = 0
+ ini_vars[7] = "noVirtual"
+ # cfgParsWrite(configFilePath)
+ # cfg_update_all()
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- prefs.SetBool('mode_virtual',0)
- say("virtual = "+str(addVirtual))
-##
+ prefs.SetBool("mode_virtual", 0)
+ say("virtual = " + str(addVirtual))
+
+ ##
def onCfg(self):
global expanded_view
global configFilePath, ini_content
- #QtGui.QMessageBox.information(None,"info ...","your home path is \r\n"+ home+"\r\n")
- #sayw(expanded_view)
- #stop
+ # QtGui.QMessageBox.information(None,"info ...","your home path is \r\n"+ home+"\r\n")
+ # sayw(expanded_view)
+ # stop
if 1:
- #if "ksuWB" not in FreeCADGui.activeWorkbench().name():
- if 'pref_page' not in globals():
+ # if "ksuWB" not in FreeCADGui.activeWorkbench().name():
+ if "pref_page" not in globals():
FreeCADGui.activateWorkbench("KiCadStepUpWB")
FreeCADGui.showPreferences("kicadStepUpGui")
- elif expanded_view!=1:
- temporary_undock() #to do ....
- #undock()
+ elif expanded_view != 1:
+ temporary_undock() # to do ....
+ # undock()
clear_console()
- ini_content=cfg_read_all()
+ ini_content = cfg_read_all()
self.textEdit.setText(ini_content)
cfg_read_all()
- #resolution = QtGui.QDesktopWidget().screenGeometry()
- #xp=(resolution.width() / 2) - sizeXMax/2 # - (KSUWidget.frameSize().width() / 2)
- #yp=(resolution.height() / 2) - sizeY/2 # - (KSUWidget.frameSize().height() / 2))
- #KSUWidget.setGeometry(xp, yp, sizeXMax, sizeY)
+ # resolution = QtGui.QDesktopWidget().screenGeometry()
+ # xp=(resolution.width() / 2) - sizeXMax/2 # - (KSUWidget.frameSize().width() / 2)
+ # yp=(resolution.height() / 2) - sizeY/2 # - (KSUWidget.frameSize().height() / 2))
+ # KSUWidget.setGeometry(xp, yp, sizeXMax, sizeY)
textEdit_dim = textEdit_dim_base
- self.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
+ self.textEdit.setGeometry(textEdit_dim[0], textEdit_dim[1], textEdit_dim[2], textEdit_dim[3])
self.textEdit.setToolTip(translate("Ui_DockWidget", "ksu config ini file\ncontent"))
- centerOnScreen (KSUWidget)
- #say("your home path is "+ expanduser("~"))
- sayw("kicad StepUp version "+str(___ver___))
- #ini_content=read_ini_file()
- expanded_view=1
- #QtCore.QTimer.singleShot(10,self.onCfg)
-
- #cfgParsRead(configFilePath)
+ centerOnScreen(KSUWidget)
+ # say("your home path is "+ expanduser("~"))
+ sayw("kicad StepUp version " + str(___ver___))
+ # ini_content=read_ini_file()
+ expanded_view = 1
+ # QtCore.QTimer.singleShot(10,self.onCfg)
+
+ # cfgParsRead(configFilePath)
else:
- #sayw(expanded_view)
- expanded_view=0
+ # sayw(expanded_view)
+ expanded_view = 0
clear_console()
- KSUWidget.setVisibility=False
- #textEdit_dim = textEdit_dim_hide
- #self.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
+ KSUWidget.setVisibility = False
+ # textEdit_dim = textEdit_dim_hide
+ # self.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
cfg_read_all()
- if docking_mode == 'float':
+ if docking_mode == "float":
undock()
- KSUWidget.setVisibility=True
- elif docking_mode == 'left':
- #tabify()
+ KSUWidget.setVisibility = True
+ elif docking_mode == "left":
+ # tabify()
dock()
- KSUWidget.setVisibility=True
+ KSUWidget.setVisibility = True
else:
dock_right()
- KSUWidget.setVisibility=True
- sayw("kicad StepUp version "+str(___ver___))
-
-# def onHide(self):
-# global expanded_view
-# global configFilePath, ini_content
-# if not expanded_view:
-# undock()
-# #resolution = QtGui.QDesktopWidget().screenGeometry()
-# #xp=(resolution.width() / 2) - sizeXMax/2 # - (KSUWidget.frameSize().width() / 2)
-# #yp=(resolution.height() / 2) - sizeY/2 # - (KSUWidget.frameSize().height() / 2))
-# #KSUWidget.setGeometry(xp, yp, sizeXMax, sizeY)
-# centerOnScreen (KSUWidget)
-# #ini_content=read_ini_file()
-# ini_content=cfg_read_all()
-# self.textEdit.setText(ini_content)
-# cfg_read_all()
-# expanded_view=True
-# #cfgParsRead(configFilePath)
-# else:
-# KSUWidget.setGeometry(250, 250, sizeX, sizeY)
-# dock_right()
-# expanded_view=False
-# #ini_content=read_ini_file()
-# ini_content=cfg_read_all()
-# self.textEdit.setText(ini_content)
-# #configParser.read(configFilePath)
-# cfg_read_all()
-# #cfgParsRead(configFilePath)
-# #global ui
-# #Dialog = QtGui.QDialog()
-# #ui = Ui_Dialog()
-# #ui.setupUi(Dialog)
-# #ui.comboBox.addItems(material_properties_names)
-# #reply=Dialog.exec_()
-#
-# #bklist = configParser.get('Blacklist', 'bklist')
-# #say(configFilePath)
-# #say(bklist)
+ KSUWidget.setVisibility = True
+ sayw("kicad StepUp version " + str(___ver___))
+
+ # def onHide(self):
+ # global expanded_view
+ # global configFilePath, ini_content
+ # if not expanded_view:
+ # undock()
+ # #resolution = QtGui.QDesktopWidget().screenGeometry()
+ # #xp=(resolution.width() / 2) - sizeXMax/2 # - (KSUWidget.frameSize().width() / 2)
+ # #yp=(resolution.height() / 2) - sizeY/2 # - (KSUWidget.frameSize().height() / 2))
+ # #KSUWidget.setGeometry(xp, yp, sizeXMax, sizeY)
+ # centerOnScreen (KSUWidget)
+ # #ini_content=read_ini_file()
+ # ini_content=cfg_read_all()
+ # self.textEdit.setText(ini_content)
+ # cfg_read_all()
+ # expanded_view=True
+ # #cfgParsRead(configFilePath)
+ # else:
+ # KSUWidget.setGeometry(250, 250, sizeX, sizeY)
+ # dock_right()
+ # expanded_view=False
+ # #ini_content=read_ini_file()
+ # ini_content=cfg_read_all()
+ # self.textEdit.setText(ini_content)
+ # #configParser.read(configFilePath)
+ # cfg_read_all()
+ # #cfgParsRead(configFilePath)
+ # #global ui
+ # #Dialog = QtGui.QDialog()
+ # #ui = Ui_Dialog()
+ # #ui.setupUi(Dialog)
+ # #ui.comboBox.addItems(material_properties_names)
+ # #reply=Dialog.exec_()
+ #
+ # #bklist = configParser.get('Blacklist', 'bklist')
+ # #say(configFilePath)
+ # #say(bklist)
-##
+ ##
def onPushPCB(self):
PushPCB()
+
# #def onExport3DStep(self):
# global last_3d_path, start_time, load_sketch
# #say("export3DSTEP")
@@ -15241,7 +16361,7 @@ def onPushPCB(self):
# msg="""Edge editing NOT supported on FC0.15!
please upgrade your FC release"""
# say_warning(msg)
# msg="Edge editing NOT supported on FC0.15!"
- # sayerr(msg)
+ # sayerr(msg)
# #if 0:
# #if FreeCAD.ActiveDocument is None:
# # FreeCAD.newDocument("PCB_Sketch")
@@ -15263,7 +16383,7 @@ def onPushPCB(self):
# testing=False
# if not testing:
# Filter=""
- # name, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Push Sketch PCB Edge to KiCad board ...",
+ # name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Push Sketch PCB Edge to KiCad board ...",
# last_3d_path, "*.kicad_pcb")
# else:
# name='d:/Temp/e2.kicad_pcb'
@@ -15278,72 +16398,69 @@ def onPushPCB(self):
# say_warning(msg)
# msg="Save to an EXISTING KiCad pcb file to update your Edge!"
# sayerr(msg)
- #
+ #
# else:
# msg="""select one Sketch to be pushed to kicad board!"""
# sayerr(msg)
# say_warning(msg)
- #
+ #
# else:
# msg="""select one Sketch to be pushed to kicad board!"""
# sayerr(msg)
# say_warning(msg)
-
-
+
# def onHelp(self):
# m = Timer (5.0,ZoomFitThread)
# m.start()
-
-
-
+
def onHelp(self):
global expanded_view
global configFilePath, ini_content, pt_osx, pt_lnx
- #QtGui.QMessageBox.information(None,"info ...","your home path is \r\n"+ home+"\r\n")
- #say("your home path is "+ expanduser("~"))
- #pm = QtGui.QPixmap()
- #pm.loadFromData(base64.b64decode(dock_left_b64))
- #sayw(expanded_view)
-
- if expanded_view!=2:
+ # QtGui.QMessageBox.information(None,"info ...","your home path is \r\n"+ home+"\r\n")
+ # say("your home path is "+ expanduser("~"))
+ # pm = QtGui.QPixmap()
+ # pm.loadFromData(base64.b64decode(dock_left_b64))
+ # sayw(expanded_view)
+
+ if expanded_view != 2:
clear_console()
cfg_read_all()
- temporary_undock() #to do ....
- #undock()
- #resolution = QtGui.QDesktopWidget().screenGeometry()
- #xp=(resolution.width() / 2) - sizeXMax/2 # - (KSUWidget.frameSize().width() / 2)
- #yp=(resolution.height() / 2) - sizeY/2 # - (KSUWidget.frameSize().height() / 2))
- #KSUWidget.setGeometry(xp, yp, sizeXMax, sizeY)
+ temporary_undock() # to do ....
+ # undock()
+ # resolution = QtGui.QDesktopWidget().screenGeometry()
+ # xp=(resolution.width() / 2) - sizeXMax/2 # - (KSUWidget.frameSize().width() / 2)
+ # yp=(resolution.height() / 2) - sizeY/2 # - (KSUWidget.frameSize().height() / 2))
+ # KSUWidget.setGeometry(xp, yp, sizeXMax, sizeY)
textEdit_dim = textEdit_dim_base
- self.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
+ self.textEdit.setGeometry(textEdit_dim[0], textEdit_dim[1], textEdit_dim[2], textEdit_dim[3])
self.textEdit.setToolTip(translate("Ui_DockWidget", "Help Start Guide"))
- centerOnScreen (KSUWidget)
- #ini_content=read_ini_file()
- font_color=""""""
- import FreeCAD, FreeCADGui
+ centerOnScreen(KSUWidget)
+ # ini_content=read_ini_file()
+ font_color = """"""
+ import FreeCAD
+ import FreeCADGui
+
# paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/MainWindow")
# if 'dark' in paramGet.GetString("StyleSheet").lower(): #we are using a StyleSheet
- font_color=""""""
- from PySide import QtGui
- font_color=""""""
- #FreeCADGui.getMainWindow().palette().background().color()
- sayw("kicad StepUp version "+str(___ver___))
- help_txt="""kicad StepUp version """+___ver___+"""
"""
- help_txt+=font_color
- help_txt+="""Kicad StepUp is a tool set to easily collaborate between kicad pcb EDA (board and 3D parts) as STEP models and FreeCAD MCAD modeler.
"""
- help_txt+=""""""
- help_txt+=font_color
+ font_color = """"""
+ font_color = """"""
+ # FreeCADGui.getMainWindow().palette().background().color()
+ sayw("kicad StepUp version " + str(___ver___))
+ help_txt = """kicad StepUp version """ + ___ver___ + """
"""
+ help_txt += font_color
+ help_txt += """Kicad StepUp is a tool set to easily collaborate between kicad pcb EDA (board and 3D parts) as STEP models and FreeCAD MCAD modeler.
"""
+ help_txt += """"""
+ help_txt += font_color
home = expanduser("~")
- ini_file_full_path=home+os.sep+'ksu-config.ini'
- ini_fname='ksu-config.ini'
- #FreeCAD.Console.PrintMessage(FreeCAD.ConfigGet("AppHomePath")+'Mod/')
- file_path_mod=FreeCAD.ConfigGet("UserAppData")+'Mod'
+ home + os.sep + "ksu-config.ini"
+ # FreeCAD.Console.PrintMessage(FreeCAD.ConfigGet("AppHomePath")+'Mod/')
+ file_path_mod = FreeCAD.ConfigGet("UserAppData") + "Mod"
if os.path.exists(file_path_mod):
- say('Mod folder exists\r\n')
- #else:
+ say("Mod folder exists\r\n")
+ # else:
# msg="missing Mod folder Module!\r\n\r\n"
# reply = QtGui.QMessageBox.information(None,"Info ...",msg)
- #if not pt_osx and not pt_lnx:
+ # if not pt_osx and not pt_lnx:
# import ksu_locator
# ksuWBpath = os.path.dirname(ksu_locator.__file__)
# #sys.path.append(ksuWB + '/Gui')
@@ -15353,379 +16470,422 @@ def onHelp(self):
# pdf_name='kicadStepUp-starter-Guide'
# help_txt+="configuration options:
Configuration options are located in the preferences system of FreeCAD, which is located in the Edit menu -> Preferences.
"
# help_txt+="starter Guide:
"+pdf_name+"
"
- #if not pt_osx and not pt_lnx:
+ # if not pt_osx and not pt_lnx:
# pdf_file_path=file_path_mod+os.sep+'ksu-wb'+os.sep+'demo'+os.sep+'kicadStepUp-starter-Guide.pdf'
# #say(pdf_file_path)
# pdf_name='kicadStepUp-starter-Guide'
# help_txt+="configuration options:
Configuration options are located in the preferences system of FreeCAD, which is located in the Edit menu -> Preferences.
"
# help_txt+="starter Guide:
"+pdf_name+"
"
- #else:
+ # else:
# #say(pdf_file_path)
# pdf_name='kicadStepUp-starter-Guide'
# help_txt+="configuration options:
Configuration options are located in the preferences system of FreeCAD, which is located in the Edit menu -> Preferences.
"
# help_txt+="starter Guide:
FC-UserAppData/Mod
"+pdf_name+"
"
import ksu_locator
+
ksuWBpath = os.path.dirname(ksu_locator.__file__)
- ksuWB_demo_path = os.path.join( ksuWBpath, 'demo')
- pdf_file_path=os.path.join(ksuWB_demo_path,'kicadStepUp-starter-Guide.pdf')
- pdf_name='kicadStepUp-cheat-sheet'
- help_txt+="configuration options:
Configuration options are located in the preferences system of FreeCAD, which is located in the Edit menu -> Preferences.
"
- help_txt+="starter Guide:
"+pdf_file_path+"
"+pdf_name+"
"
- help_txt+="kicadStepUp-cheat-sheet.pdf
"
- #help_txt+="
"
- help_txt+="StepUp can be used to align 3D model to kicad footprint.
"
- help_txt+="The artwork can be used for MCAD interchange and collaboration, and for enclosure design.
"
- help_txt+="The 3D visualization of components on board assemblies in kicad 3dviewer, will be the same in your mechanical software, "
- help_txt+="because of the STEP interchange format.
"
- help_txt+="It is also possible to Update a pcb Edge from a FC Sketcher.
"
- help_txt+="
First of all: configure your path to 3D models in
FreeCAD Preferences Page
"
- help_txt+="Note: each button has its own Tooltip
"
- help_txt+="useful buttons:
Load kicad Board directly -> will load kicad board and parts in FreeCAD coming from kicad '.kicad_pcb' file
"
- help_txt+="Load kicad Footprint module -> will load directly kicad footprint in FreeCAD to easily align the 3D model to footprint
"
- help_txt+="Export to kicad STEP & scaled VRML -> will convert MCAD model to STEP and VRML to be used by Kicad and kicad StepUp
"
- help_txt+=" -> VRML can be multipart;
-> STEP must be single part
('Part Boolean Union' or 'Part Makecompound')
"
- help_txt+="assign material to selected colors and your VRML 3D models will have nice shiny effects
"
- help_txt+="Push pcb Sketch to kicad_pcb Edge -> will push pcb Sketch to kicad_pcb Edge in your design; it can be done with an empty or with an existing pcb Edge
"
- help_txt+="
for a more detailed help have a look at
kicadStepUp-starter-Guide.pdf
"
- help_txt+="or just follow the YouTube video tutorials
kicadStepUp basics
"
- help_txt+="kicadStepUp STEP alignment to Kicad footprint
"
- help_txt+="check always the latest release of kicadStepUp
"
- help_txt+="Designing in kicad native 3d-viewer will produce a fully aligned STEP MCAD version "
- help_txt+="with the same view of kicad 3d render.
"
- help_txt+="Moreover, KiCad StepUp tool set will let you to load the kicad footprint inside FreeCAD and align the 3D part with a visual real time feedback "
- help_txt+="of the 3d model and footprint reciprocal position.
"
- help_txt+="With this tool is possible to download a part from on-line libraries, align the model to kicad footprint "
- help_txt+="and export the model to wrl, for immediate 3d-viewer alignment in pcbnew.
"
- help_txt+="Now the two words are connected for a better collaboration; just design in kicad EDA and transfer "
- help_txt+="the artwork to MCAD (FreeCAD) smoothly.
"
- help_txt+="The workflow is very simple and maintains the usual way to work with kicad:
"
- help_txt+="Add models to your library creating 3D models in FreeCAD, or getting models from online libs "
- help_txt+="or from the parametric 3D lib expressly done to kicad kicadStepUp 3D STEP models generator
"
- help_txt+="Once you have your 3D MCAD model, you need to have a copy of that in STEP and VRML format.
"
- help_txt+="(with the latest kicad release you can only have STEP model, VRML is not needed anymore, but it is possible"
- help_txt+=" to mix VRML, STEP and IGES format)
"
- help_txt+="Just exporting the model with FreeCAD and put your model in the same folder in which "
- help_txt+="normally you are used to put vrml models; the script will assembly the MCAD board and models as in 3d-viewer of kicad."
- help_txt+="
NB
STEP model has to be fused in single object
(Part Boolean Union of objects)"
- help_txt+="
or a Compoud (Part Makecompound of objects)"
- help_txt+="
enable 'Report view' Panel to see helping messages"
- help_txt+=""
- help_txt+="
"
+ ksuWB_demo_path = os.path.join(ksuWBpath, "demo")
+ pdf_file_path = os.path.join(ksuWB_demo_path, "kicadStepUp-starter-Guide.pdf")
+ pdf_name = "kicadStepUp-cheat-sheet"
+ help_txt += "configuration options:
Configuration options are located in the preferences system of FreeCAD, which is located in the Edit menu -> Preferences.
"
+ help_txt += "starter Guide:
" + pdf_file_path + "
" + pdf_name + "
"
+ help_txt += "kicadStepUp-cheat-sheet.pdf
"
+ # help_txt+="
"
+ help_txt += "StepUp can be used to align 3D model to kicad footprint.
"
+ help_txt += "The artwork can be used for MCAD interchange and collaboration, and for enclosure design.
"
+ help_txt += "The 3D visualization of components on board assemblies in kicad 3dviewer, will be the same in your mechanical software, "
+ help_txt += "because of the STEP interchange format.
"
+ help_txt += "It is also possible to Update a pcb Edge from a FC Sketcher.
"
+ help_txt += "
First of all: configure your path to 3D models in
FreeCAD Preferences Page
"
+ help_txt += "Note: each button has its own Tooltip
"
+ help_txt += "useful buttons:
Load kicad Board directly -> will load kicad board and parts in FreeCAD coming from kicad '.kicad_pcb' file
"
+ help_txt += "Load kicad Footprint module -> will load directly kicad footprint in FreeCAD to easily align the 3D model to footprint
"
+ help_txt += "Export to kicad STEP & scaled VRML -> will convert MCAD model to STEP and VRML to be used by Kicad and kicad StepUp
"
+ help_txt += " -> VRML can be multipart;
-> STEP must be single part
('Part Boolean Union' or 'Part Makecompound')
"
+ help_txt += (
+ "assign material to selected colors and your VRML 3D models will have nice shiny effects
"
+ )
+ help_txt += "Push pcb Sketch to kicad_pcb Edge -> will push pcb Sketch to kicad_pcb Edge in your design; it can be done with an empty or with an existing pcb Edge
"
+ help_txt += "
for a more detailed help have a look at
kicadStepUp-starter-Guide.pdf
"
+ help_txt += "or just follow the YouTube video tutorials
kicadStepUp basics
"
+ help_txt += "kicadStepUp STEP alignment to Kicad footprint
"
+ help_txt += "check always the latest release of kicadStepUp
"
+ help_txt += "Designing in kicad native 3d-viewer will produce a fully aligned STEP MCAD version "
+ help_txt += "with the same view of kicad 3d render.
"
+ help_txt += "Moreover, KiCad StepUp tool set will let you to load the kicad footprint inside FreeCAD and align the 3D part with a visual real time feedback "
+ help_txt += "of the 3d model and footprint reciprocal position.
"
+ help_txt += "With this tool is possible to download a part from on-line libraries, align the model to kicad footprint "
+ help_txt += "and export the model to wrl, for immediate 3d-viewer alignment in pcbnew.
"
+ help_txt += "Now the two words are connected for a better collaboration; just design in kicad EDA and transfer "
+ help_txt += "the artwork to MCAD (FreeCAD) smoothly.
"
+ help_txt += "The workflow is very simple and maintains the usual way to work with kicad:
"
+ help_txt += "Add models to your library creating 3D models in FreeCAD, or getting models from online libs "
+ help_txt += "or from the parametric 3D lib expressly done to kicad kicadStepUp 3D STEP models generator
"
+ help_txt += (
+ "Once you have your 3D MCAD model, you need to have a copy of that in STEP and VRML format.
"
+ )
+ help_txt += "(with the latest kicad release you can only have STEP model, VRML is not needed anymore, but it is possible"
+ help_txt += " to mix VRML, STEP and IGES format)
"
+ help_txt += "Just exporting the model with FreeCAD and put your model in the same folder in which "
+ help_txt += "normally you are used to put vrml models; the script will assembly the MCAD board and models as in 3d-viewer of kicad."
+ help_txt += (
+ "
NB
STEP model has to be fused in single object
(Part Boolean Union of objects)"
+ )
+ help_txt += "
or a Compoud (Part Makecompound of objects)"
+ help_txt += "
enable 'Report view' Panel to see helping messages"
+ help_txt += ""
+ help_txt += "
"
self.textEdit.setText(help_txt)
- #self.textEdit.setTextColor(QtGui.QColor('black'))
- #self.textEdit.setStyleSheet("background-color: rgb(255, 255, 255)");
+ # self.textEdit.setTextColor(QtGui.QColor('black'))
+ # self.textEdit.setStyleSheet("background-color: rgb(255, 255, 255)");
# to reset it to default color ...
- #txtEdit->setStyleSheet("");
- expanded_view=2
- #cfgParsRead(configFilePath)
+ # txtEdit->setStyleSheet("");
+ expanded_view = 2
+ # cfgParsRead(configFilePath)
else:
- expanded_view=0
+ expanded_view = 0
clear_console()
- KSUWidget.setVisibility=False
- #textEdit_dim = textEdit_dim_hide
- #self.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
+ KSUWidget.setVisibility = False
+ # textEdit_dim = textEdit_dim_hide
+ # self.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
cfg_read_all()
- if docking_mode == 'float':
+ if docking_mode == "float":
undock()
- KSUWidget.setVisibility=True
- elif docking_mode == 'left':
- #tabify()
+ KSUWidget.setVisibility = True
+ elif docking_mode == "left":
+ # tabify()
dock()
- KSUWidget.setVisibility=True
+ KSUWidget.setVisibility = True
else:
dock_right()
- KSUWidget.setVisibility=True
- sayw("kicad StepUp version "+str(___ver___))
- #self.textEdit.setStyleSheet("");
- #say('onHelp')
- #reply = QtGui.QMessageBox.question(None, "", "step file exists, overwrite?",QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
+ KSUWidget.setVisibility = True
+ sayw("kicad StepUp version " + str(___ver___))
+ # self.textEdit.setStyleSheet("");
+ # say('onHelp')
+ # reply = QtGui.QMessageBox.question(None, "", "step file exists, overwrite?",QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.No)
+
+
##
## sketch testing button
+
def Export3DStepF():
global last_3d_path, last_pcb_path, stp_exp_mode, use_AppPart, use_Links, links_imp_mode, use_LinkGroups
-
- #say("export3DSTEP")
+
+ # say("export3DSTEP")
sel = FreeCADGui.Selection.getSelection()
- if len (sel) > 0:
- #sayw(doc.Name)
+ if len(sel) > 0:
+ # sayw(doc.Name)
if "App::Part" in sel[0].TypeId and not use_AppPart:
- msg="""App::Part hierarchy cannot be exported ATM
use the buttons to make a Union or Compound before exporting it"""
- say_warning(msg)
+ msg = """App::Part hierarchy cannot be exported ATM
use the buttons to make a Union or Compound before exporting it"""
+ say_warning(msg)
else:
cfg_read_all()
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- last_3d_path = pg.GetString("last_3d_path")
+ last_3d_path = pg.GetString("last_3d_path")
if len(last_3d_path) == 0:
- last_3d_path=last_pcb_path
+ last_3d_path = last_pcb_path
sayw(last_pcb_path)
- #getSaveFileName(self,"saveFlle","Result.txt",filter ="txt (*.txt *.)")
- def_fn=sel[0].Label
- Filter=""
- prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if prefs_.GetBool('stpz_export_enabled'):
- ext_='.stpZ'
+ # getSaveFileName(self,"saveFlle","Result.txt",filter ="txt (*.txt *.)")
+ def_fn = sel[0].Label
+ if not (prefs_.GetBool("not_native_dlg")):
+ name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName(
+ None,
+ "Export 3D STEP/stpZ ...",
+ make_unicode(os.path.join(last_3d_path, def_fn) + ext_),
+ "*.step *.stp *.stpZ *.stpz",
+ )
else:
- ext_='.step'
- if not(prefs_.GetBool('not_native_dlg')):
- name, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Export 3D STEP/stpZ ...",
- make_unicode(os.path.join(last_3d_path,def_fn)+ext_), "*.step *.stp *.stpZ *.stpz")
- else:
- name, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Export 3D STEP/stpZ ...",
- make_unicode(os.path.join(last_3d_path,def_fn)+ext_), "*.step *.stp *.stpZ *.stpz",options=QtWidgets.QFileDialog.DontUseNativeDialog)
- #say(name)
+ name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName(
+ None,
+ "Export 3D STEP/stpZ ...",
+ make_unicode(os.path.join(last_3d_path, def_fn) + ext_),
+ "*.step *.stp *.stpZ *.stpz",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
+ # say(name)
if name:
- doc=FreeCAD.ActiveDocument
- doc.openTransaction('exp3D')
- last_3d_path=os.path.dirname(name)
+ doc = FreeCAD.ActiveDocument
+ doc.openTransaction("exp3D")
+ last_3d_path = os.path.dirname(name)
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- pg.SetString("last_3d_path",make_string(last_3d_path))
- #my_sk=FreeCAD.ActiveDocument.copyObject(FreeCAD.ActiveDocument.PCB_Sketch,False)
- #my_sk_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #FreeCAD.ActiveDocument.removeObject(FreeCAD.ActiveDocument.PCB_Sketch.Name)
- #ImportGui.export(sel,name)
+ pg.SetString("last_3d_path", make_string(last_3d_path))
+ # my_sk=FreeCAD.ActiveDocument.copyObject(FreeCAD.ActiveDocument.PCB_Sketch,False)
+ # my_sk_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ # FreeCAD.ActiveDocument.removeObject(FreeCAD.ActiveDocument.PCB_Sketch.Name)
+ # ImportGui.export(sel,name)
## PCB_Sketch=FreeCAD.ActiveDocument.copyObject(FreeCAD.ActiveDocument.getObject(my_sk_name),False)
- #cpy_sketch(my_sk_name,"PCB_Sketch")
- #FreeCAD.ActiveDocument.removeObject(my_sk_name)
- #FreeCAD.ActiveDocument.getObject("Board_Geoms").addObject(FreeCAD.ActiveDocument.getObject("PCB_Sketch"))
+ # cpy_sketch(my_sk_name,"PCB_Sketch")
+ # FreeCAD.ActiveDocument.removeObject(my_sk_name)
+ # FreeCAD.ActiveDocument.getObject("Board_Geoms").addObject(FreeCAD.ActiveDocument.getObject("PCB_Sketch"))
sel = FreeCADGui.Selection.getSelection()
- selN=sel[0].Name
+ selN = sel[0].Name
doc = FreeCAD.ActiveDocument
- #sayw(stp_exp_mode)
- #stop
- #deselect Sketches
+ # sayw(stp_exp_mode)
+ # stop
+ # deselect Sketches
if not use_AppPart:
for e in sel:
- if 'Sketch' in e.TypeId:
+ if "Sketch" in e.TypeId:
FreeCADGui.Selection.removeSelection(FreeCAD.ActiveDocument.getObject(e.Name))
sel = FreeCADGui.Selection.getSelection()
- if 'Local_CS_' in e.Name:
+ if "Local_CS_" in e.Name:
FreeCADGui.Selection.removeSelection(FreeCAD.ActiveDocument.getObject(e.Name))
sel = FreeCADGui.Selection.getSelection()
else:
- #skl=[sk,grp]
- skl=[]
- skl=find_skt_in_Doc()
- #print skl
- #print sk_name,';',grp_name
+ # skl=[sk,grp]
+ skl = []
+ skl = find_skt_in_Doc()
+ # print skl
+ # print sk_name,';',grp_name
for sk in skl:
- say('moving sketch from grp')
- #print sk
+ say("moving sketch from grp")
+ # print sk
FreeCAD.ActiveDocument.getObject(sk[1]).removeObject(FreeCAD.ActiveDocument.getObject(sk[0]))
- #FreeCAD.ActiveDocument.getObject(selN).removeObject(FreeCAD.ActiveDocument.getObject(sk_name))
- #stop
+ # FreeCAD.ActiveDocument.getObject(selN).removeObject(FreeCAD.ActiveDocument.getObject(sk_name))
+ # stop
fcv = getFCversion()
fcb = checkFCbug(fcv)
# sayerr('not fcb '+str(not fcb))
# sayw(stp_exp_mode)
# say(fcv[0])
- if (stp_exp_mode == 'hierarchy' and not fcb) or (fcv[0]==0 and fcv[1]<=16): # FC not bugged or < 0.17
- sayw('exporting hierarchy')
- if name.lower().endswith('step') or name.lower().endswith('stp'):
- ImportGui.export(sel,name)
+ if (stp_exp_mode == "hierarchy" and not fcb) or (
+ fcv[0] == 0 and fcv[1] <= 16
+ ): # FC not bugged or < 0.17
+ sayw("exporting hierarchy")
+ if name.lower().endswith("step") or name.lower().endswith("stp"):
+ ImportGui.export(sel, name)
else:
try:
import stepZ
- stepZ.export(sel,name)
+
+ stepZ.export(sel, name)
except:
- sayerr('.stpZ not supported!')
- step_name=name
- if float(FreeCAD.Version()[0])==1 and float(FreeCAD.Version()[1])==0: ## FC 1.0.x
+ sayerr(".stpZ not supported!")
+ step_name = name
+ if float(FreeCAD.Version()[0]) == 1 and float(FreeCAD.Version()[1]) == 0: ## FC 1.0.x
import step_amend
- found_transp_issue=step_amend.transp_rmv(step_name)
+
+ found_transp_issue = step_amend.transp_rmv(step_name)
if found_transp_issue:
- sayw(step_name+' file amended')
- elif (stp_exp_mode == 'onelevel') or (stp_exp_mode == 'hierarchy' and fcb):
- sayw('exporting ONE level hierarchy')
+ sayw(step_name + " file amended")
+ elif (stp_exp_mode == "onelevel") or (stp_exp_mode == "hierarchy" and fcb):
+ sayw("exporting ONE level hierarchy")
try:
import kicadStepUpCMD
except:
- sayerr('to export STEP it is necessary to use StepUp Workbench
instead of the single Macro
(because of '+str(fcv)+' FC bug)')
- msg="""to export STEP it is necessary to use StepUp Workbench
instead of the single Macro
(because of """+str(fcv)+""" FC bug"""
+ sayerr(
+ "to export STEP it is necessary to use StepUp Workbench
instead of the single Macro
(because of "
+ + str(fcv)
+ + " FC bug)",
+ )
+ msg = (
+ """to export STEP it is necessary to use StepUp Workbench
instead of the single Macro
(because of """
+ + str(fcv)
+ + """ FC bug"""
+ )
say_warning(msg)
for sk in skl:
- say('including sketch in grp')
+ say("including sketch in grp")
FreeCAD.ActiveDocument.getObject(sk[1]).addObject(FreeCAD.ActiveDocument.getObject(sk[0]))
stop
- if fcb:
- cpmode='compound'
- else:
- cpmode='part'
- suffix='_'
- to_export_name=kicadStepUpCMD.deep_copy(doc,cpmode,suffix)
+ cpmode = "compound" if fcb else "part"
+ suffix = "_"
+ to_export_name = kicadStepUpCMD.deep_copy(doc, cpmode, suffix)
# to_export_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #sayw(FreeCAD.ActiveDocument.getObject(to_export_name).Label)
- #say(sel[0])
- __objs__=[]
+ # sayw(FreeCAD.ActiveDocument.getObject(to_export_name).Label)
+ # say(sel[0])
+ __objs__ = []
__objs__.append(FreeCAD.ActiveDocument.getObject(to_export_name))
- #import ImportGui
- if name.lower().endswith('step') or name.lower().endswith('stp'):
- ImportGui.export(__objs__,name)
+ # import ImportGui
+ if name.lower().endswith("step") or name.lower().endswith("stp"):
+ ImportGui.export(__objs__, name)
else:
try:
import stepZ
- stepZ.export(__objs__,name)
+
+ stepZ.export(__objs__, name)
except:
- sayerr('.stpZ not supported!')
- step_name=name
- if float(FreeCAD.Version()[0])==1 and float(FreeCAD.Version()[1])==0: ## FC 1.0.x
+ sayerr(".stpZ not supported!")
+ step_name = name
+ if float(FreeCAD.Version()[0]) == 1 and float(FreeCAD.Version()[1]) == 0: ## FC 1.0.x
import step_amend
- found_transp_issue=step_amend.transp_rmv(step_name)
+
+ found_transp_issue = step_amend.transp_rmv(step_name)
if found_transp_issue:
- sayw(step_name+' file amended')
- #FreeCAD.ActiveDocument.removeObject(to_export_nam)
+ sayw(step_name + " file amended")
+ # FreeCAD.ActiveDocument.removeObject(to_export_nam)
removesubtree(__objs__)
del __objs__
- if fcb: # bugged FC version
- sayerr('exported a simplified STEP hierarchy because of '+str(fcv)+' FC bug')
- msg="""exported a simplified STEP hierarchy
because of """+str(fcv)+""" FC bug"""
+ if fcb: # bugged FC version
+ sayerr("exported a simplified STEP hierarchy because of " + str(fcv) + " FC bug")
+ msg = (
+ """exported a simplified STEP hierarchy
because of """
+ + str(fcv)
+ + """ FC bug"""
+ )
say_warning(msg)
- #FreeCADGui.Selection.removeSelection(sel[0])
- #FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(to_export_name))
- #sel1 = FreeCADGui.Selection.getSelection()
- #say(sel1[0])
- #ImportGui.export(sel1[0],name)
- #stop
- elif stp_exp_mode == 'flat':
+ # FreeCADGui.Selection.removeSelection(sel[0])
+ # FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(to_export_name))
+ # sel1 = FreeCADGui.Selection.getSelection()
+ # say(sel1[0])
+ # ImportGui.export(sel1[0],name)
+ # stop
+ elif stp_exp_mode == "flat":
# need to deselect all 'Part' containers and select all simple objs
- #say('flat')
- if len(sel)==1 and 'App::Part' in sel[0].TypeId: ## flattening a Part hierarchy container
- sayw('flattening Part container')
+ # say('flat')
+ if len(sel) == 1 and "App::Part" in sel[0].TypeId: ## flattening a Part hierarchy container
+ sayw("flattening Part container")
# FreeCADGui.Selection.removeSelection(sel[0])
- __objs__=[]
+ __objs__ = []
# sayerr(FreeCAD.ActiveDocument.getObject(selN).Label)
# sayerr(FreeCAD.ActiveDocument.getObject(selN).OutListRecursive)
for o in FreeCAD.ActiveDocument.getObject(selN).OutListRecursive:
- #sayw( o.TypeId )
- #if 'Part::Feature' in o.TypeId:
- if hasattr(o, 'Shape'):
+ # sayw( o.TypeId )
+ # if 'Part::Feature' in o.TypeId:
+ if hasattr(o, "Shape"):
# print o.Label
- # say ('adding ')
+ # say ('adding ')
# FreeCADGui.Selection.addSelection(o)
__objs__.append(o)
- if name.lower().endswith('step') or name.lower().endswith('stp'):
- ImportGui.export(__objs__,name)
+ if name.lower().endswith("step") or name.lower().endswith("stp"):
+ ImportGui.export(__objs__, name)
else:
try:
import stepZ
- stepZ.export(__objs__,name)
+
+ stepZ.export(__objs__, name)
except:
- sayerr('.stpZ not supported!')
- step_name=name
- if float(FreeCAD.Version()[0])==1 and float(FreeCAD.Version()[1])==0: ## FC 1.0.x
+ sayerr(".stpZ not supported!")
+ step_name = name
+ if float(FreeCAD.Version()[0]) == 1 and float(FreeCAD.Version()[1]) == 0: ## FC 1.0.x
import step_amend
- found_transp_issue=step_amend.transp_rmv(step_name)
+
+ found_transp_issue = step_amend.transp_rmv(step_name)
if found_transp_issue:
- sayw(step_name+' file amended')
+ sayw(step_name + " file amended")
del __objs__
else:
- sayw('exporting selection')
- ImportGui.export(sel,name)
-
- #print selN,'-',sk_name
- #FreeCAD.ActiveDocument.getObject(selN).removeObject(App.ActiveDocument.getObject(sk_name))
+ sayw("exporting selection")
+ ImportGui.export(sel, name)
+
+ # print selN,'-',sk_name
+ # FreeCAD.ActiveDocument.getObject(selN).removeObject(App.ActiveDocument.getObject(sk_name))
if use_AppPart:
for sk in skl:
- say('including sketch in grp')
+ say("including sketch in grp")
FreeCAD.ActiveDocument.getObject(sk[1]).addObject(FreeCAD.ActiveDocument.getObject(sk[0]))
doc.commitTransaction()
# PCB_Sketch=FreeCAD.ActiveDocument.copyObject(FreeCAD.ActiveDocument.getObject(my_sk_name),False)
- #try:
+ # try:
# FreeCAD.ActiveDocument.getObject(selN).addObject(FreeCAD.ActiveDocument.getObject(sk_name))
- #except:
+ # except:
# sayw('no PCB_Sketch2')
# pass
else:
- msg="""select something to be exported!"""
+ msg = """select something to be exported!"""
sayerr(msg)
say_warning(msg)
-
-##
+
+
+##
+
def Import3DModelF():
-
+
global last_3d_path, last_pcb_path
global zfit
-
+
say("import3DModel")
- #sayw(doc.Name)
+ # sayw(doc.Name)
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- last_3d_path = pg.GetString("last_3d_path")
+ last_3d_path = pg.GetString("last_3d_path")
cfg_read_all()
if len(last_3d_path) == 0:
- last_3d_path=last_pcb_path
+ last_3d_path = last_pcb_path
sayw(last_pcb_path)
- Filter=""
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if not(prefs_.GetBool('not_native_dlg')):
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Import 3D File...",
- make_unicode(last_3d_path), "*.step *.stp *.stpZ *.iges *.igs *.FCStd")
+ if not (prefs_.GetBool("not_native_dlg")):
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Import 3D File...",
+ make_unicode(last_3d_path),
+ "*.step *.stp *.stpZ *.iges *.igs *.FCStd",
+ )
else:
- name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Import 3D File...",
- make_unicode(last_3d_path), "*.step *.stp *.stpZ *.iges *.igs *.FCStd",options=QtWidgets.QFileDialog.DontUseNativeDialog)
+ name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Import 3D File...",
+ make_unicode(last_3d_path),
+ "*.step *.stp *.stpZ *.iges *.igs *.FCStd",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
- #say(name)
+ # say(name)
if name:
ext = os.path.splitext(os.path.basename(name))[1]
- #sayw(ext.lower())
+ # sayw(ext.lower())
if ext.lower() == ".fcstd":
FreeCAD.open(name)
else:
if FreeCAD.ActiveDocument is None:
- #say("none")
- doc=FreeCAD.newDocument()
+ # say("none")
+ doc = FreeCAD.newDocument()
else:
- doc=FreeCAD.ActiveDocument
+ doc = FreeCAD.ActiveDocument
##ReadShapeCompoundMode
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- ReadShapeCompoundMode_status=paramGetVS.GetBool("ReadShapeCompoundMode")
- #sayerr("checking ReadShapeCompoundMode")
- sayw("ReadShapeCompoundMode status "+str(ReadShapeCompoundMode_status))
- enable_ReadShapeCompoundMode=False
+ ReadShapeCompoundMode_status = paramGetVS.GetBool("ReadShapeCompoundMode")
+ # sayerr("checking ReadShapeCompoundMode")
+ sayw("ReadShapeCompoundMode status " + str(ReadShapeCompoundMode_status))
+ enable_ReadShapeCompoundMode = False
if ReadShapeCompoundMode_status:
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- paramGetVS.SetBool("ReadShapeCompoundMode",False)
+ paramGetVS.SetBool("ReadShapeCompoundMode", False)
sayw("disabling ReadShapeCompoundMode")
- enable_ReadShapeCompoundMode=True
-
+ enable_ReadShapeCompoundMode = True
+
FreeCAD.setActiveDocument(doc.Name)
- FreeCAD.ActiveDocument=FreeCAD.getDocument(doc.Name)
- FreeCADGui.ActiveDocument=FreeCADGui.getDocument(doc.Name)
- if name.lower().endswith('stpz'):
+ FreeCAD.ActiveDocument = FreeCAD.getDocument(doc.Name)
+ FreeCADGui.ActiveDocument = FreeCADGui.getDocument(doc.Name)
+ if name.lower().endswith("stpz"):
try:
import stepZ
- stepZ.insert(name,doc.Name)
+
+ stepZ.insert(name, doc.Name)
except:
- sayerr('.stpZ not supported!')
+ sayerr(".stpZ not supported!")
else:
ImportGui.insert(name, doc.Name)
-
- #enable_ReadShapeCompoundMode=False
+
+ # enable_ReadShapeCompoundMode=False
if enable_ReadShapeCompoundMode:
paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP")
- paramGetVS.SetBool("ReadShapeCompoundMode",True)
+ paramGetVS.SetBool("ReadShapeCompoundMode", True)
sayw("enabling ReadShapeCompoundMode")
-
- if (zfit):
+
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- last_3d_path=os.path.dirname(name)
+ last_3d_path = os.path.dirname(name)
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- pg.SetString("last_3d_path",make_string(last_3d_path))
-
+ pg.SetString("last_3d_path", make_string(last_3d_path))
+
+
##
-#import PySide
-#from PySide import QtCore, QtGui #, QtWidgets
+# import PySide
+# from PySide import QtCore, QtGui #, QtWidgets
##from PyQt5 import QtCore, QtGui, QtWidgets
QtWidgets = QtGui
-class Ui_STEP_Preferences(object):
+
+class Ui_STEP_Preferences:
def setupUi(self, STEP_Preferences):
import os
- import ksu_locator
+
ksuWBpath = os.path.dirname(ksu_locator.__file__)
- #sys.path.append(ksuWB + '/Gui')
- ksuWB_demo_path = os.path.join( ksuWBpath, 'demo')
+ # sys.path.append(ksuWB + '/Gui')
+ ksuWB_demo_path = os.path.join(ksuWBpath, "demo")
STEP_Preferences.setObjectName("STEP_Preferences")
STEP_Preferences.resize(860, 752)
STEP_Preferences.setWindowTitle("STEP Suggested Preferences")
@@ -15744,7 +16904,7 @@ def setupUi(self, STEP_Preferences):
self.verticalLayout_2.addWidget(self.label)
self.label_2 = QtWidgets.QLabel(self.verticalLayoutWidget)
self.label_2.setText("")
- self.label_2.setPixmap(QtGui.QPixmap(os.path.join(ksuWB_demo_path,"Import-Export-settings.png")))
+ self.label_2.setPixmap(QtGui.QPixmap(os.path.join(ksuWB_demo_path, "Import-Export-settings.png")))
self.label_2.setObjectName("label_2")
self.verticalLayout_2.addWidget(self.label_2)
self.label_3 = QtWidgets.QLabel(self.verticalLayoutWidget)
@@ -15770,8 +16930,9 @@ def setupUi(self, STEP_Preferences):
def retranslateUi(self, STEP_Preferences):
pass
+
##
-class Ui_LayerSelection(object):
+class Ui_LayerSelection:
def setupUi(self, LayerSelection):
LayerSelection.setObjectName("LayerSelection")
LayerSelection.resize(341, 232)
@@ -15780,7 +16941,7 @@ def setupUi(self, LayerSelection):
self.buttonBoxLayer = QtWidgets.QDialogButtonBox(LayerSelection)
self.buttonBoxLayer.setGeometry(QtCore.QRect(60, 190, 271, 32))
self.buttonBoxLayer.setOrientation(QtCore.Qt.Horizontal)
- self.buttonBoxLayer.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
+ self.buttonBoxLayer.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok)
self.buttonBoxLayer.setObjectName("buttonBoxLayer")
self.verticalLayoutWidget = QtWidgets.QWidget(LayerSelection)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 325, 171))
@@ -15791,8 +16952,7 @@ def setupUi(self, LayerSelection):
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.label = QtWidgets.QLabel(self.verticalLayoutWidget)
- self.label.setText("Select the layer to push the Sketch\n"
-"Default \'Edge.Cuts\'")
+ self.label.setText("Select the layer to push the Sketch\nDefault 'Edge.Cuts'")
self.label.setObjectName("label")
self.verticalLayout_2.addWidget(self.label)
self.verticalLayout.addLayout(self.verticalLayout_2)
@@ -15806,12 +16966,22 @@ def setupUi(self, LayerSelection):
self.radioBtn_newdoc.setObjectName("radioBtn_newdoc")
self.verticalLayout.addWidget(self.radioBtn_newdoc)
self.radioBtn_replace_pcb = QtWidgets.QRadioButton(self.verticalLayoutWidget)
- self.radioBtn_replace_pcb.setToolTip(translate("Ui_LayerSelection", "replace PCB in current document
N.B. Sketch constrains will be deleted!
"))
+ self.radioBtn_replace_pcb.setToolTip(
+ translate(
+ "Ui_LayerSelection",
+ 'replace PCB in current document
N.B. Sketch constrains will be deleted!
',
+ ),
+ )
self.radioBtn_replace_pcb.setText(translate("Ui_LayerSelection", "replace PCB and Sketch in current document"))
self.radioBtn_replace_pcb.setObjectName("radioBtn_replace_pcb")
self.verticalLayout.addWidget(self.radioBtn_replace_pcb)
self.radioBtn_keep_sketch = QtWidgets.QRadioButton(self.verticalLayoutWidget)
- self.radioBtn_keep_sketch.setToolTip(translate("Ui_LayerSelection", "keep Sketch in current document
N.B. this option will keep Sketch & constrains but replace the PCB
This could lead to a unsynced Sketch feature
"))
+ self.radioBtn_keep_sketch.setToolTip(
+ translate(
+ "Ui_LayerSelection",
+ 'keep Sketch in current document
N.B. this option will keep Sketch & constrains but replace the PCB
This could lead to a unsynced Sketch feature
',
+ ),
+ )
self.radioBtn_keep_sketch.setText(translate("Ui_LayerSelection", "replace PCB and keep Sketch in curr. doc"))
self.radioBtn_keep_sketch.setObjectName("radioBtn_keep_sketch")
self.verticalLayout.addWidget(self.radioBtn_keep_sketch)
@@ -15820,26 +16990,28 @@ def setupUi(self, LayerSelection):
self.buttonBoxLayer.accepted.connect(LayerSelection.accept)
self.buttonBoxLayer.rejected.connect(LayerSelection.reject)
QtCore.QMetaObject.connectSlotsByName(LayerSelection)
-#-------#-------------------------------------------------------------------------
- self.comboBoxLayerSel.currentTextChanged.connect(self.on_combobox_changed) #addition
+ # -------#-------------------------------------------------------------------------
+ self.comboBoxLayerSel.currentTextChanged.connect(self.on_combobox_changed) # addition
def retranslateUi(self, LayerSelection):
pass
-
+
def on_combobox_changed(self, value):
- #print('combo change',value)
- if value != 'Edge.Cuts':
- #self.radioBtn_newdoc.setChecked(True)
+ # print('combo change',value)
+ if value != "Edge.Cuts":
+ # self.radioBtn_newdoc.setChecked(True)
self.radioBtn_replace_pcb.setChecked(True)
- #self.radioBtn_replace_pcb.setEnabled(False)
+ # self.radioBtn_replace_pcb.setEnabled(False)
self.radioBtn_keep_sketch.setEnabled(False)
self.radioBtn_replace_pcb.setEnabled(True)
self.radioBtn_replace_pcb.setText("import Layer in active document")
else:
self.radioBtn_replace_pcb.setEnabled(True)
self.radioBtn_keep_sketch.setEnabled(True)
+
+
##
-class Ui_LayerSelectionOut(object):
+class Ui_LayerSelectionOut:
def setupUi(self, LayerSelectionOut):
LayerSelectionOut.setObjectName("LayerSelectionOut")
LayerSelectionOut.resize(293, 249)
@@ -15848,7 +17020,7 @@ def setupUi(self, LayerSelectionOut):
self.buttonBoxLayer = QtWidgets.QDialogButtonBox(LayerSelectionOut)
self.buttonBoxLayer.setGeometry(QtCore.QRect(10, 200, 271, 32))
self.buttonBoxLayer.setOrientation(QtCore.Qt.Horizontal)
- self.buttonBoxLayer.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
+ self.buttonBoxLayer.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok)
self.buttonBoxLayer.setObjectName("buttonBoxLayer")
self.verticalLayoutWidget = QtWidgets.QWidget(LayerSelectionOut)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 271, 80))
@@ -15859,7 +17031,7 @@ def setupUi(self, LayerSelectionOut):
self.verticalLayout_2 = QtWidgets.QVBoxLayout()
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.label = QtWidgets.QLabel(self.verticalLayoutWidget)
- self.label.setText("Select the layer to push the Sketch\nDefault \'Edge.Cuts\'")
+ self.label.setText("Select the layer to push the Sketch\nDefault 'Edge.Cuts'")
self.label.setObjectName("label")
self.verticalLayout_2.addWidget(self.label)
self.verticalLayout.addLayout(self.verticalLayout_2)
@@ -15878,7 +17050,7 @@ def setupUi(self, LayerSelectionOut):
self.width_label.setMinimumSize(QtCore.QSize(150, 0))
self.width_label.setToolTip("")
self.width_label.setText(translate("Ui_LayerSelectionOut", "Line Width:"))
- self.width_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
+ self.width_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter)
self.width_label.setObjectName("width_label")
self.horizontalLayout.addWidget(self.width_label)
self.lineEdit_width = QtWidgets.QLineEdit(self.verticalLayoutWidget_2)
@@ -15893,34 +17065,37 @@ def setupUi(self, LayerSelectionOut):
self.buttonBoxLayer.rejected.connect(LayerSelectionOut.reject)
QtCore.QMetaObject.connectSlotsByName(LayerSelectionOut)
-#-------#-------------------------------------------------------------------------
- self.comboBoxLayerSel.currentTextChanged.connect(self.on_combobox_changed) #addition
+ # -------#-------------------------------------------------------------------------
+ self.comboBoxLayerSel.currentTextChanged.connect(self.on_combobox_changed) # addition
def retranslateUi(self, LayerSelectionOut):
pass
-
+
def on_combobox_changed(self, value):
- #print('combo change',value)
- if 'Zone' in value:
+ # print('combo change',value)
+ if "Zone" in value:
self.lineEdit_width.setEnabled(False)
self.width_label.setEnabled(False)
- #self.width_label.setText("-----:")
+ # self.width_label.setText("-----:")
else:
self.lineEdit_width.setEnabled(True)
self.width_label.setEnabled(True)
+
+
##
+
def PushPCB():
-#def onExport3DStep(self):
+ # def onExport3DStep(self):
global last_3d_path, start_time, load_sketch, last_pcb_path, edge_width
- #say("export3DSTEP")
- if load_sketch==False:
+ # say("export3DSTEP")
+ if not load_sketch:
msg = translate("PushPCB", "Edge editing NOT supported on FC0.15!
please upgrade your FC release")
say_warning(msg)
msg = translate("PushPCB", "Edge editing NOT supported on FC0.15!")
- sayerr(msg)
- #if 0:
- #if FreeCAD.ActiveDocument is None:
+ sayerr(msg)
+ # if 0:
+ # if FreeCAD.ActiveDocument is None:
# FreeCAD.newDocument("PCB_Sketch")
# PCB_Sketch= FreeCAD.activeDocument().addObject('Sketcher::SketchObject','PCB_Sketch')
# offset=[0.0,0.0] #offset=[148.5,98.5]
@@ -15929,94 +17104,126 @@ def PushPCB():
# FreeCADGui.SendMsgToActiveView("ViewFit")
else:
sel = FreeCADGui.Selection.getSelection()
- if len (sel) == 1:
- #sayw(doc.Name)
+ if len(sel) == 1:
+ # sayw(doc.Name)
if "Sketch" in sel[0].TypeId:
if 0:
- from pivy import coin
from math import degrees
+
+ from pivy import coin
+
print(translate("PushPCB", "getting camera view"))
pcam = FreeCADGui.ActiveDocument.ActiveView.getCamera()
sketch = sel[0]
rot = sketch.getGlobalPlacement().Rotation
- print(rot,degrees(rot.Angle), float(rot.Angle))
+ print(rot, degrees(rot.Angle), float(rot.Angle))
cam = FreeCADGui.ActiveDocument.ActiveView.getCameraNode()
if rot.Angle < 0.001:
rot.Angle = 0
- print (translate("PushPCB", "forcing rotAngle to 0"))
- cam.orientation.setValue(coin.SbVec3f(rot.Axis.x, rot.Axis.y, rot.Axis.z), rot.Angle) #-pi)
+ print(translate("PushPCB", "forcing rotAngle to 0"))
+ cam.orientation.setValue(coin.SbVec3f(rot.Axis.x, rot.Axis.y, rot.Axis.z), rot.Angle) # -pi)
FreeCADGui.ActiveDocument.ActiveView.fitAll()
print(translate("PushPCB", "evaluate to recompute"))
FreeCAD.ActiveDocument.recompute()
- #sel[0].ViewObject.Visibility = False
- #print(sel[0].Label)
- #sel[0].recompute(True)
+ # sel[0].ViewObject.Visibility = False
+ # print(sel[0].Label)
+ # sel[0].recompute(True)
cfg_read_all()
if len(last_pcb_path) == 0:
last_pcb_path = ""
# last_3d_path=last_pcb_path
# sayw(last_pcb_path)
- #getSaveFileName(self,"saveFlle","Result.txt",filter ="txt (*.txt *.)")
+ # getSaveFileName(self,"saveFlle","Result.txt",filter ="txt (*.txt *.)")
# layer_list = ['Edge.Cuts','Dwgs.User','Cmts.User','Eco1.User','Eco2.User','Margin', 'F.FillZone', 'F.KeepOutZone', 'F.MaskZone','B.FillZone', 'B.KeepOutZone', 'B.MaskZone',]
- layer_list = ['Edge.Cuts','Dwgs.User','Cmts.User','Eco1.User','Eco2.User','User.1','User.2','User.3','User.4','User.5','User.6','User.7','User.8','User.9','Margin', 'F.FillZone', 'F.KeepOutZone', 'F.MaskZone','B.FillZone', 'B.KeepOutZone', 'B.MaskZone',]
+ layer_list = [
+ "Edge.Cuts",
+ "Dwgs.User",
+ "Cmts.User",
+ "Eco1.User",
+ "Eco2.User",
+ "User.1",
+ "User.2",
+ "User.3",
+ "User.4",
+ "User.5",
+ "User.6",
+ "User.7",
+ "User.8",
+ "User.9",
+ "Margin",
+ "F.FillZone",
+ "F.KeepOutZone",
+ "F.MaskZone",
+ "B.FillZone",
+ "B.KeepOutZone",
+ "B.MaskZone",
+ ]
LayerSelectionDlg = QtGui.QDialog()
ui = Ui_LayerSelectionOut()
ui.setupUi(LayerSelectionDlg)
ui.comboBoxLayerSel.addItems(layer_list)
if 0:
ui.comboBoxLayerSel.setEditable(True)
- reply=LayerSelectionDlg.exec_()
- if reply==1: # ok
- SketchLayer=str(ui.comboBoxLayerSel.currentText())
- if 1: #'Edge' not in SketchLayer:
- edge_width=float(ui.lineEdit_width.text().replace(',','.'))
+ reply = LayerSelectionDlg.exec_()
+ if reply == 1: # ok
+ SketchLayer = str(ui.comboBoxLayerSel.currentText())
+ if 1: #'Edge' not in SketchLayer:
+ edge_width = float(ui.lineEdit_width.text().replace(",", "."))
print(SketchLayer)
- skname=sel[0].Name
- #else: #canel
- # print('Cancel')
- # stop
- # pass
- testing=False
+ skname = sel[0].Name
+ # else: #canel
+ # print('Cancel')
+ # stop
+ # pass
+ testing = False
if not testing:
- Filter=""
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if not(prefs_.GetBool('not_native_dlg')):
- name, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Push Sketch PCB Edge to KiCad board ...",
- make_unicode(last_pcb_path), "*.kicad_pcb")
+ if not (prefs_.GetBool("not_native_dlg")):
+ name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName(
+ None,
+ "Push Sketch PCB Edge to KiCad board ...",
+ make_unicode(last_pcb_path),
+ "*.kicad_pcb",
+ )
else:
- name, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Push Sketch PCB Edge to KiCad board ...",
- make_unicode(last_pcb_path), "*.kicad_pcb",options=QtWidgets.QFileDialog.DontUseNativeDialog)
+ name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName(
+ None,
+ "Push Sketch PCB Edge to KiCad board ...",
+ make_unicode(last_pcb_path),
+ "*.kicad_pcb",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
else:
- name='d:/Temp/e2.kicad_pcb'
- #say(name)
+ name = "d:/Temp/e2.kicad_pcb"
+ # say(name)
if name:
if os.path.exists(name):
- last_pcb_path=os.path.dirname(name)
+ last_pcb_path = os.path.dirname(name)
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- pg.SetString("last_pcb_path",make_string(last_pcb_path))
- start_time=current_milli_time()
- export_pcb(name,SketchLayer,skname)
+ pg.SetString("last_pcb_path", make_string(last_pcb_path))
+ start_time = current_milli_time()
+ export_pcb(name, SketchLayer, skname)
else:
if not (name.endswith("kicad_pcb")):
name = name + ".kicad_pcb"
- msg = translate("PushPCB", "Saving to an empty KiCad pcb file")+'\n'+name
+ msg = translate("PushPCB", "Saving to an empty KiCad pcb file") + "\n" + name
sayw(msg)
- last_pcb_path=os.path.dirname(name)
+ last_pcb_path = os.path.dirname(name)
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- pg.SetString("last_pcb_path",make_string(last_pcb_path))
+ pg.SetString("last_pcb_path", make_string(last_pcb_path))
import ksu_locator
+
ksuWBpath = os.path.dirname(ksu_locator.__file__)
- ksuWB_demo_path = os.path.join( ksuWBpath, 'demo')
- copyfile(os.path.join(ksuWB_demo_path,'empty-kv5.kicad_pcb'), name)
- start_time=current_milli_time()
- export_pcb(name,SketchLayer,skname)
+ ksuWB_demo_path = os.path.join(ksuWBpath, "demo")
+ copyfile(os.path.join(ksuWB_demo_path, "empty-kv5.kicad_pcb"), name)
+ start_time = current_milli_time()
+ export_pcb(name, SketchLayer, skname)
# msg="""Save to an EXISTING KiCad pcb file to update your Edge!"""
# say_warning(msg)
# msg="Save to an EXISTING KiCad pcb file to update your Edge!"
# sayerr(msg)
- else: #cancel
+ else: # cancel
print(translate("PushPCB", "Cancel"))
- pass
if 0:
print(translate("PushPCB", "Restoring cam view"))
FreeCADGui.ActiveDocument.ActiveView.setCamera(pcam)
@@ -16025,11 +17232,13 @@ def PushPCB():
msg = translate("PushPCB", "Select one Sketch to be pushed to kicad board!")
sayerr(msg)
say_warning(msg)
-
+
else:
msg = translate("PushPCB", "Select one Sketch to be pushed to kicad board!")
sayerr(msg)
say_warning(msg)
+
+
##
def Sync3DModel():
global last_3d_path, start_time
@@ -16041,83 +17250,91 @@ def Sync3DModel():
global original_filename, aux_orig, grid_orig
global off_x, off_y, maxRadius, use_pypro
- import fcad_parser
- from fcad_parser import KicadPCB,SexpList
- import kicad_parser
-
- #say("export3DSTEP")
- if load_sketch==False:
- msg="""Board editing NOT supported on FC0.15!
please upgrade your FC release"""
+ # say("export3DSTEP")
+ if not load_sketch:
+ msg = """Board editing NOT supported on FC0.15!
please upgrade your FC release"""
say_warning(msg)
- msg="Board editing NOT supported on FC0.15!"
- sayerr(msg)
+ msg = "Board editing NOT supported on FC0.15!"
+ sayerr(msg)
else:
sel = FreeCADGui.Selection.getSelection()
- if len (sel) == 1:
- if hasattr(sel[0],"Shape") or "Link" in sel[0].TypeId:
+ if len(sel) == 1:
+ if hasattr(sel[0], "Shape") or "Link" in sel[0].TypeId:
cfg_read_all()
if len(last_pcb_path) == 0:
last_pcb_path = ""
- #sayw(last_pcb_path)
- #getSaveFileName(self,"saveFlle","Result.txt",filter ="txt (*.txt *.)")
- testing=False
+ # sayw(last_pcb_path)
+ # getSaveFileName(self,"saveFlle","Result.txt",filter ="txt (*.txt *.)")
+ testing = False
if not testing:
- Filter=""
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if not(prefs_.GetBool('not_native_dlg')):
- fname, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Load KiCad PCB board data...",
- make_unicode(last_pcb_path), "*.kicad_pcb")
+ if not (prefs_.GetBool("not_native_dlg")):
+ fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Load KiCad PCB board data...",
+ make_unicode(last_pcb_path),
+ "*.kicad_pcb",
+ )
else:
- fname, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Load KiCad PCB board data...",
- make_unicode(last_pcb_path), "*.kicad_pcb",options=QtWidgets.QFileDialog.DontUseNativeDialog)
+ fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Load KiCad PCB board data...",
+ make_unicode(last_pcb_path),
+ "*.kicad_pcb",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
else:
- fname='c:/Temp/demo/demo-test-mp.kicad_pcb'
+ fname = "c:/Temp/demo/demo-test-mp.kicad_pcb"
if fname is not None:
if os.path.exists(fname):
- last_pcb_path=os.path.dirname(fname)
+ last_pcb_path = os.path.dirname(fname)
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- pg.SetString("last_pcb_path",make_string(last_pcb_path))
- start_time=current_milli_time()
- doc=FreeCAD.ActiveDocument
- #filePath=last_pcb_path
- #fpath=filePath+os.sep+doc.Label+'.kicad_pcb'
- #sayerr('to '+fpath)
- #print fname
- if fname is None:
- fpath=original_filename
- else:
- fpath=fname
- sayerr('Loading from '+fpath)
- #stop
+ pg.SetString("last_pcb_path", make_string(last_pcb_path))
+ start_time = current_milli_time()
+ # filePath=last_pcb_path
+ # fpath=filePath+os.sep+doc.Label+'.kicad_pcb'
+ # sayerr('to '+fpath)
+ # print fname
+ fpath = original_filename if fname is None else fname
+ sayerr("Loading from " + fpath)
+ # stop
if len(fpath) > 0:
- #new_edge_list=getBoardOutline()
- #say (new_edge_list)
+ # new_edge_list=getBoardOutline()
+ # say (new_edge_list)
cfg_read_all()
- path, fname = os.path.split(fpath)
- name=os.path.splitext(fname)[0]
- ext=os.path.splitext(fname)[1]
+ _path, fname = os.path.split(fpath)
+ os.path.splitext(fname)[0]
+ os.path.splitext(fname)[1]
fpth = os.path.dirname(os.path.abspath(fpath))
- #filePath = os.path.split(os.path.realpath(__file__))[0]
- say ('file path '+fpth); say('kicad board file: '+fname)
+ # filePath = os.path.split(os.path.realpath(__file__))[0]
+ say("file path " + fpth)
+ say("kicad board file: " + fname)
# stop
if fpth == "":
fpth = "."
last_pcb_path = fpth
last_pcb_path = re.sub("\\\\", "/", last_pcb_path)
ini_vars[10] = last_pcb_path
- #cfg_update_all()
- #sayerr(name+':'+ext)
+ # cfg_update_all()
+ # sayerr(name+':'+ext)
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
pg.SetString("last_pcb_path", make_string(last_pcb_path))
mypcb = KicadPCB.load(fpath)
- reply=False;ref_found=False;input_ref=''
- #input_ref = QtGui.QInputDialog.getText(None, 'Sync Ref', 'Reference to be synced',QtGui.QLineEdit.EchoMode.Normal,'REF#',reply)
- input_ref = QtGui.QInputDialog.getText(None, 'Sync Ref', 'Reference to be synced',QtGui.QLineEdit.EchoMode.Normal,'REF#') #,reply)
- #print (reply);print('*');print input_ref
+ ref_found = False
+ input_ref = ""
+ # input_ref = QtGui.QInputDialog.getText(None, 'Sync Ref', 'Reference to be synced',QtGui.QLineEdit.EchoMode.Normal,'REF#',reply)
+ input_ref = QtGui.QInputDialog.getText(
+ None,
+ "Sync Ref",
+ "Reference to be synced",
+ QtGui.QLineEdit.EchoMode.Normal,
+ "REF#",
+ ) # ,reply)
+ # print (reply);print('*');print input_ref
if len(input_ref) > 1:
if input_ref[1]:
- matching_Reference=input_ref[0] #'LD1'
- matching_TimeStamp='Null'
+ matching_Reference = input_ref[0] #'LD1'
+ matching_TimeStamp = "Null"
for m in mypcb.module:
Ref = get_mod_Ref(m)
## try:
@@ -16127,93 +17344,134 @@ def Sync3DModel():
## ## Ref = m.property[0][1] #kv8 fp reference
## except:
## Ref = m.fp_text[0][1]
- #Ref = m.property[0][1] #kv8 fp reference
+ # Ref = m.property[0][1] #kv8 fp reference
# print(m.property[0]);print(Ref);print(len(Ref))
- #print(m.property[0]);print(m.property[0][0]);print(m.property[0][1]);
+ # print(m.property[0]);print(m.property[0][0]);print(m.property[0][1]);
if Ref.lstrip('"').rstrip('"') == matching_Reference:
- say ('found Reference: '+Ref)
- ref_found=True
- if hasattr(m,'tstamp') or hasattr(m,'uuid'):
- if hasattr(m,'tstamp'):
- matching_TimeStamp=m.tstamp
- elif hasattr(m,'uuid'):
- matching_TimeStamp=m.uuid.rstrip('"')
- say ('linked TimeStamp: '+matching_TimeStamp)
- if sel[0].Label.rfind('_') < sel[0].Label.rfind('['):
- ts = sel[0].Label[sel[0].Label.rfind('_')+1:sel[0].Label.rfind('[')]
- nbrModel = sel[0].Label[sel[0].Label.rfind('['):]
+ say("found Reference: " + Ref)
+ ref_found = True
+ if hasattr(m, "tstamp") or hasattr(m, "uuid"):
+ if hasattr(m, "tstamp"):
+ matching_TimeStamp = m.tstamp
+ elif hasattr(m, "uuid"):
+ matching_TimeStamp = m.uuid.rstrip('"')
+ say("linked TimeStamp: " + matching_TimeStamp)
+ if sel[0].Label.rfind("_") < sel[0].Label.rfind("["):
+ ts = sel[0].Label[
+ sel[0].Label.rfind("_") + 1 : sel[0].Label.rfind("[")
+ ]
+ nbrModel = sel[0].Label[sel[0].Label.rfind("[") :]
else:
- ts = sel[0].Label[sel[0].Label.rfind('_')+1:] # tstamp
- nbrModel = ''
- #ts = sel[0].Label[sel[0].Label.rfind('_')+1:]
- #mmodel=m.model[0][0]
- #print (mmodel[mmodel.rfind('/')+1:mmodel.rfind('.')]);stop
- if len (m.model)>0:
- if nbrModel == '':
- mmodel=m.model[0][0]
+ ts = sel[0].Label[sel[0].Label.rfind("_") + 1 :] # tstamp
+ nbrModel = ""
+ # ts = sel[0].Label[sel[0].Label.rfind('_')+1:]
+ # mmodel=m.model[0][0]
+ # print (mmodel[mmodel.rfind('/')+1:mmodel.rfind('.')]);stop
+ if len(m.model) > 0:
+ if nbrModel == "":
+ mmodel = m.model[0][0]
else:
- nMd=int(nbrModel.replace('[','').replace(']',''))-1
- #print (nMd)
- mmodel=m.model[nMd][0]
- if mmodel.rfind('/') !=-1:
- mmodel=mmodel[mmodel.rfind('/')+1:mmodel.rfind('.')]
+ nMd = int(nbrModel.replace("[", "").replace("]", "")) - 1
+ # print (nMd)
+ mmodel = m.model[nMd][0]
+ if mmodel.rfind("/") != -1:
+ mmodel = mmodel[mmodel.rfind("/") + 1 : mmodel.rfind(".")]
else:
- mmodel=mmodel[mmodel.rfind('\\')+1:mmodel.rfind('.')]
+ mmodel = mmodel[mmodel.rfind("\\") + 1 : mmodel.rfind(".")]
else:
- mmodel=''
- if ((len (ts) != 8) and (len (ts) != 12)) or sel[0].Label.rfind('_') == -1:
- msg="TimeStamp not found!\nAdding & Syncing Ref & TimeStamp"
+ mmodel = ""
+ if ((len(ts) != 8) and (len(ts) != 12)) or sel[0].Label.rfind(
+ "_",
+ ) == -1:
+ msg = "TimeStamp not found!\nAdding & Syncing Ref & TimeStamp"
sayw(msg)
- if len (mmodel)>0:
- sel[0].Label=Ref+'_'+mmodel.replace('.','')+'_'+matching_TimeStamp+nbrModel
+ if len(mmodel) > 0:
+ sel[0].Label = (
+ Ref
+ + "_"
+ + mmodel.replace(".", "")
+ + "_"
+ + matching_TimeStamp
+ + nbrModel
+ )
else:
- sel[0].Label=Ref+'_'+sel[0].Label+'_'+matching_TimeStamp+nbrModel
+ sel[0].Label = (
+ Ref
+ + "_"
+ + sel[0].Label
+ + "_"
+ + matching_TimeStamp
+ + nbrModel
+ )
else:
if len(matching_TimeStamp) > 8:
- matching_TimeStamp=matching_TimeStamp[-12:]
- if len (mmodel)>0:
- sel[0].Label=Ref.lstrip('"').rstrip('"')+'_'+mmodel.replace('.','')+'_'+matching_TimeStamp+nbrModel
+ matching_TimeStamp = matching_TimeStamp[-12:]
+ if len(mmodel) > 0:
+ sel[0].Label = (
+ Ref.lstrip('"').rstrip('"')
+ + "_"
+ + mmodel.replace(".", "")
+ + "_"
+ + matching_TimeStamp
+ + nbrModel
+ )
else:
- sel[0].Label=Ref.lstrip('"').rstrip('"')+sel[0].Label[sel[0].Label.find('_'):sel[0].Label.rfind('_')+1]+matching_TimeStamp+nbrModel
- msg="Adding & Syncing Ref & TimeStamp"
- say(msg)
- #sel[0].Label=Ref+sel[0].Label[sel[0].Label.index('_'):sel[0].Label.rindex('_')+1]+matching_TimeStamp
- msg="""3D model Reference & TimeStamp synced
with the Reference """+Ref+""" of the kicad board!
"""
- msgr="3D model Reference & TimeStamp synced\nwith the Reference "+Ref+" of the kicad board!"
+ sel[0].Label = (
+ Ref.lstrip('"').rstrip('"')
+ + sel[0].Label[
+ sel[0].Label.find("_") : sel[0].Label.rfind("_") + 1
+ ]
+ + matching_TimeStamp
+ + nbrModel
+ )
+ msg = "Adding & Syncing Ref & TimeStamp"
+ say(msg)
+ # sel[0].Label=Ref+sel[0].Label[sel[0].Label.index('_'):sel[0].Label.rindex('_')+1]+matching_TimeStamp
+ msg = (
+ """3D model Reference & TimeStamp synced
with the Reference """
+ + Ref
+ + """ of the kicad board!
"""
+ )
+ msgr = (
+ "3D model Reference & TimeStamp synced\nwith the Reference "
+ + Ref
+ + " of the kicad board!"
+ )
say(msgr)
say_info(msg)
else:
- sayerr('Reference: '+Ref+' is missing TimeStamp field')
- msg="""Reference: """+Ref+""" is missing TimeStamp field"""
+ sayerr("Reference: " + Ref + " is missing TimeStamp field")
+ msg = """Reference: """ + Ref + """ is missing TimeStamp field"""
say_warning(msg)
if not ref_found:
- sayerr('Reference: '+matching_Reference+' not found!')
- msg="""Reference: """+matching_Reference+""" not found!"""
+ sayerr("Reference: " + matching_Reference + " not found!")
+ msg = """Reference: """ + matching_Reference + """ not found!"""
say_warning(msg)
else:
- msg="""Operation aborted!"""
+ msg = """Operation aborted!"""
sayerr(msg)
say_info(msg)
- #model_data=re.findall('\s\(module(\s'+matching_Reference+'\s.+?)\(at',data, re.MULTILINE|re.DOTALL)
- #model_data=re.findall('\s\(fp_text\s(reference\s'+matching_Reference'+'\s.+?)\(at,data, re.MULTILINE|re.DOTALL)
+ # model_data=re.findall('\s\(module(\s'+matching_Reference+'\s.+?)\(at',data, re.MULTILINE|re.DOTALL)
+ # model_data=re.findall('\s\(fp_text\s(reference\s'+matching_Reference'+'\s.+?)\(at,data, re.MULTILINE|re.DOTALL)
else:
- msg="""Load an EXISTING KiCad pcb file to sync your 3D model Reference & TimeStamp!"""
+ msg = """Load an EXISTING KiCad pcb file to sync your 3D model Reference & TimeStamp!"""
say_warning(msg)
- msg="Load an EXISTING KiCad pcb file to sync your 3D model Reference & TimeStamp!"
+ msg = "Load an EXISTING KiCad pcb file to sync your 3D model Reference & TimeStamp!"
sayerr(msg)
else:
- msg="""select one 3D model to sync its TimeStamp based on its Reference in the kicad board!"""
+ msg = """select one 3D model to sync its TimeStamp based on its Reference in the kicad board!"""
sayerr(msg)
say_warning(msg)
else:
- msg="""Operation aborted!"""
+ msg = """Operation aborted!"""
sayerr(msg)
say_info(msg)
else:
- msg="""select one 3D model to sync its TimeStamp based on its Reference in the kicad board!"""
+ msg = """select one 3D model to sync its TimeStamp based on its Reference in the kicad board!"""
sayerr(msg)
say_warning(msg)
+
###
def PushMoved():
global last_3d_path, start_time
@@ -16225,379 +17483,402 @@ def PushMoved():
global original_filename, aux_orig, grid_orig
global off_x, off_y, maxRadius, use_pypro
- import fcad_parser
- from fcad_parser import KicadPCB,SexpList
- import kicad_parser
-
## to export to STEP an object and its links with a different placement and label
## two options must be set: 1) disable 'Reduce number of objects'; 2) disable 'Ignore instance names'
## NB the second one is not good for collaboration with different cads
-
- #say("export3DSTEP")
- if load_sketch==False:
- msg="""Board editing NOT supported on FC0.15!
please upgrade your FC release"""
+
+ # say("export3DSTEP")
+ if not load_sketch:
+ msg = """Board editing NOT supported on FC0.15!
please upgrade your FC release"""
say_warning(msg)
- msg="Board editing NOT supported on FC0.15!"
- sayerr(msg)
+ msg = "Board editing NOT supported on FC0.15!"
+ sayerr(msg)
else:
- check_ok=False
+ check_ok = False
sel = FreeCADGui.Selection.getSelection()
- if len (sel) >= 1:
+ if len(sel) >= 1:
for s in sel:
- if s.Label.rfind('_') < s.Label.rfind('['):
- ts = s.Label[s.Label.rfind('_')+1:s.Label.rfind('[')]
+ if s.Label.rfind("_") < s.Label.rfind("["):
+ ts = s.Label[s.Label.rfind("_") + 1 : s.Label.rfind("[")]
else:
- ts = s.Label[s.Label.rfind('_')+1:]
- if len (ts) == 8 or len (ts) == 12: # NB kv8 enlarged uuid to 32+4 chrs
- #print(ts);stop
- check_ok=True
- #stop
+ ts = s.Label[s.Label.rfind("_") + 1 :]
+ if len(ts) == 8 or len(ts) == 12: # NB kv8 enlarged uuid to 32+4 chrs
+ # print(ts);stop
+ check_ok = True
+ # stop
break
- #else:
+ # else:
# msg="""select only 3D model(s) moved to be updated/pushed to kicad board!
a TimeSTamp is required!"""
# sayerr(msg)
# say_warning(msg)
if check_ok:
cfg_read_all()
- #pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- #pg.GetString("last_3d_path")
+ # pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
+ # pg.GetString("last_3d_path")
if len(last_pcb_path) == 0:
- last_pcb_path=u''
- #sayw(last_pcb_path)
- #getSaveFileName(self,"saveFlle","Result.txt",filter ="txt (*.txt *.)")
- testing=False #True
+ last_pcb_path = ""
+ # sayw(last_pcb_path)
+ # getSaveFileName(self,"saveFlle","Result.txt",filter ="txt (*.txt *.)")
+ testing = False # True
if not testing:
- Filter=""
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if not(prefs_.GetBool('not_native_dlg')):
- fname, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Push 3D PCB position(s) to KiCad board ...",
- make_unicode(last_pcb_path), "*.kicad_pcb")
+ if not (prefs_.GetBool("not_native_dlg")):
+ fname, _Filter = PySide.QtGui.QFileDialog.getSaveFileName(
+ None,
+ "Push 3D PCB position(s) to KiCad board ...",
+ make_unicode(last_pcb_path),
+ "*.kicad_pcb",
+ )
else:
- fname, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Push 3D PCB position(s) to KiCad board ...",
- make_unicode(last_pcb_path), "*.kicad_pcb",options=QtWidgets.QFileDialog.DontUseNativeDialog)
+ fname, _Filter = PySide.QtGui.QFileDialog.getSaveFileName(
+ None,
+ "Push 3D PCB position(s) to KiCad board ...",
+ make_unicode(last_pcb_path),
+ "*.kicad_pcb",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
else:
- fname='c:/Temp/demo/test-rot.kicad_pcb'
+ fname = "c:/Temp/demo/test-rot.kicad_pcb"
if fname:
if os.path.exists(fname):
- last_3d_path=os.path.dirname(fname)
+ last_3d_path = os.path.dirname(fname)
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- pg.SetString("last_3d_path",make_string(last_3d_path))
- start_time=current_milli_time()
- doc=FreeCAD.ActiveDocument
- #filePath=last_pcb_path
- #fpath=filePath+os.sep+doc.Label+'.kicad_pcb'
- #sayerr('to '+fpath)
- #print fname
- if fname is None:
- fpath=original_filename
- else:
- fpath=fname
- sayerr('saving to '+fpath)
- #stop
+ pg.SetString("last_3d_path", make_string(last_3d_path))
+ start_time = current_milli_time()
+ # filePath=last_pcb_path
+ # fpath=filePath+os.sep+doc.Label+'.kicad_pcb'
+ # sayerr('to '+fpath)
+ # print fname
+ fpath = original_filename if fname is None else fname
+ sayerr("saving to " + fpath)
+ # stop
if len(fpath) > 0:
- #new_edge_list=getBoardOutline()
- #say (new_edge_list)
+ # new_edge_list=getBoardOutline()
+ # say (new_edge_list)
cfg_read_all()
path, fname = os.path.split(fpath)
- name=os.path.splitext(fname)[0]
- ext=os.path.splitext(fname)[1]
+ name = os.path.splitext(fname)[0]
+ ext = os.path.splitext(fname)[1]
fpth = os.path.dirname(os.path.abspath(fpath))
- #filePath = os.path.split(os.path.realpath(__file__))[0]
- say ('my file path '+fpth)
+ # filePath = os.path.split(os.path.realpath(__file__))[0]
+ say("my file path " + fpth)
# stop
if fpth == "":
fpth = "."
last_pcb_path = fpth
last_pcb_path = re.sub("\\\\", "/", last_pcb_path)
ini_vars[10] = last_pcb_path
- #cfg_update_all()
+ # cfg_update_all()
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
pg.SetString("last_pcb_path", make_string(last_pcb_path))
- #sayerr(name+':'+ext)
- #mypcb = KicadPCB.load(fpath)
- with codecs.open(fpath,'r', encoding='utf-8') as txtFile:
- content = txtFile.readlines() # problems?
- content.append(u" ")
+ # sayerr(name+':'+ext)
+ # mypcb = KicadPCB.load(fpath)
+ with codecs.open(fpath, "r", encoding="utf-8") as txtFile:
+ content = txtFile.readlines() # problems?
+ content.append(" ")
txtFile.close()
- data=u''.join(content)
- tml= time.localtime()
- now=str(tml.tm_year)+'-'+str(tml.tm_mon)+'-'+str(tml.tm_mday)+'-'+str(tml.tm_hour)+'.'+str(tml.tm_min)+'.'+str(tml.tm_sec)
- #foname=os.path.join(path, name+'-bkp-'+now+ext+'-bak')
- foname=os.path.join(path, name+u'-bkp-'+make_unicode(now)+ext+u'-bak')
- oft=None
+ data = "".join(content)
+ tml = time.localtime()
+ now = (
+ str(tml.tm_year)
+ + "-"
+ + str(tml.tm_mon)
+ + "-"
+ + str(tml.tm_mday)
+ + "-"
+ + str(tml.tm_hour)
+ + "."
+ + str(tml.tm_min)
+ + "."
+ + str(tml.tm_sec)
+ )
+ # foname=os.path.join(path, name+'-bkp-'+now+ext+'-bak')
+ foname = os.path.join(path, name + "-bkp-" + make_unicode(now) + ext + "-bak")
+ oft = None
if aux_orig == 1:
- oft=getAuxOrigin(data)
+ oft = getAuxOrigin(data)
elif grid_orig == 1:
- oft=getGridOrigin(data)
- #print oft
- gof=False
- origin_warn=False
+ oft = getGridOrigin(data)
+ # print oft
+ origin_warn = False
if oft is not None:
- if oft == [0.0,0.0]:
- origin_warn=True
- off_x=oft[0];off_y=-oft[1]
- offset = oft
- gof=True
- pcb_push=True
+ if oft == [0.0, 0.0]:
+ origin_warn = True
+ off_x = oft[0]
+ off_y = -oft[1]
+ pcb_push = True
else:
- pcb_push=False
- testing=False #True
+ pcb_push = False
+ testing = False # True
if testing is not True:
try:
- #with codecs.open(foname,'w', encoding='utf-8') as ofile:
+ # with codecs.open(foname,'w', encoding='utf-8') as ofile:
# ofile.write(data)
# ofile.close()
copyfile(fpath, foname)
- say('file copied')
+ say("file copied")
except:
- msg="""problem in writing permissions to kicad board!
"""
- msg+="file saving aborted to
"+fpath+"
"
- msgr="problem in writing permissions to kicad board!\n"
- msgr+="file saving aborted to "+fpath+"\n"
- pcb_push=False
+ msg = """problem in writing permissions to kicad board!
"""
+ msg += "file saving aborted to
" + fpath + "
"
+ msgr = "problem in writing permissions to kicad board!\n"
+ msgr += "file saving aborted to " + fpath + "\n"
+ pcb_push = False
say(msgr)
say_info(msg)
if pcb_push:
mdp = 0
for s in sel:
- #sayw(doc.Name)
+ # sayw(doc.Name)
if use_pypro:
- if hasattr(s,"TimeStamp"):
- ts=s.TimeStamp
- content = push3D2pcb(s,content,ts)
+ if hasattr(s, "TimeStamp"):
+ ts = s.TimeStamp
+ content = push3D2pcb(s, content, ts)
else:
- msg="""select only 3D model(s) moved to be updated/pushed to kicad board!"""
+ msg = """select only 3D model(s) moved to be updated/pushed to kicad board!"""
sayerr(msg)
say_warning(msg)
else:
- if s.Label.rfind('_') < s.Label.rfind('['):
- ts = s.Label[s.Label.rfind('_')+1:s.Label.rfind('[')]
+ if s.Label.rfind("_") < s.Label.rfind("["):
+ ts = s.Label[s.Label.rfind("_") + 1 : s.Label.rfind("[")]
else:
- ts = s.Label[s.Label.rfind('_')+1:]
- if len (ts) == 8 or len (ts) == 12:
- mdp+=1
- #print(ts);stop
- content = push3D2pcb(s,content,ts)
- #else:
+ ts = s.Label[s.Label.rfind("_") + 1 :]
+ if len(ts) == 8 or len(ts) == 12:
+ mdp += 1
+ # print(ts);stop
+ content = push3D2pcb(s, content, ts)
+ # else:
# msg="""select only 3D model(s) moved to be updated/pushed to kicad board!
a TimeSTamp is required!"""
# sayerr(msg)
# say_warning(msg)
- newcontent=u''.join(content)
- #pcbTracks=re.findall('\s\(tracks(\s.+?)\)',data, re.MULTILINE|re.DOTALL)
- found_tracks=True
- if 0: # forcing found tracks to true 'cause kicad 6 doesn't write it anymore inside the file
- pcbTracks=re.findall('\s\(tracks(\s.+?)\)',data, re.MULTILINE|re.DOTALL)
- found_tracks=False
- if len(pcbTracks)>0:
+ newcontent = "".join(content)
+ # pcbTracks=re.findall('\s\(tracks(\s.+?)\)',data, re.MULTILINE|re.DOTALL)
+ found_tracks = True
+ if 0: # forcing found tracks to true 'cause kicad 6 doesn't write it anymore inside the file
+ pcbTracks = re.findall(r"\s\(tracks(\s.+?)\)", data, re.MULTILINE | re.DOTALL)
+ found_tracks = False
+ if len(pcbTracks) > 0:
try:
if (float(pcbTracks[0])) > 0:
- found_tracks=True
+ found_tracks = True
except:
- found_tracks=True
- with codecs.open(fpath,'w', encoding='utf-8') as ofile:
+ found_tracks = True
+ with codecs.open(fpath, "w", encoding="utf-8") as ofile:
ofile.write(newcontent)
- ofile.close()
+ ofile.close()
say_time()
- say('pushed '+str(mdp)+' model(s)')
- msg="""3D model new position(s) pushed to kicad board!
["""+str(mdp)+""" model(s) updated]
"""
+ say("pushed " + str(mdp) + " model(s)")
+ msg = (
+ """3D model new position(s) pushed to kicad board!
["""
+ + str(mdp)
+ + """ model(s) updated]
"""
+ )
if found_tracks:
- msg+="in case of tracks
you will need to fix your routing!
"
- msg+="file saved to
"+fpath+"
"
- msg+="backup file saved to
"+foname+"
"
- msgr="3D model new position pushed to kicad board!\n"
- msgr+="file saved to "+fpath+"\n"
- msgr+="backup file saved to "+foname
+ msg += "in case of tracks
you will need to fix your routing!
"
+ msg += "file saved to
" + fpath + "
"
+ msg += "backup file saved to
" + foname + "
"
+ msgr = "3D model new position pushed to kicad board!\n"
+ msgr += "file saved to " + fpath + "\n"
+ msgr += "backup file saved to " + foname
say(msgr)
say_info(msg)
if origin_warn:
if aux_orig == 1:
- origin_msg='AuxOrigin'
+ origin_msg = "AuxOrigin"
elif grid_orig == 1:
- origin_msg='GridOrigin'
- msg = origin_msg +' is set in FC Preferences but not set in KiCAD pcbnew file'
+ origin_msg = "GridOrigin"
+ msg = origin_msg + " is set in FC Preferences but not set in KiCAD pcbnew file"
sayw(msg)
- msg=""""""+origin_msg+""" is set in FreeCAD Preferences
but not set in KiCAD pcbnew file"""
- msg+="""
Please assign """+origin_msg+""" to your KiCAD pcbnew board file"""
- msg+="""
for a better Mechanical integration"""
+ msg = (
+ """"""
+ + origin_msg
+ + """ is set in FreeCAD Preferences
but not set in KiCAD pcbnew file"""
+ )
+ msg += """
Please assign """ + origin_msg + """ to your KiCAD pcbnew board file"""
+ msg += """
for a better Mechanical integration"""
say_warning(msg)
else:
- msg="""To update 3D model Position(s) in an EXISTING KiCad pcb file
the KiCAD pcbnew board file must have assigned \'Grid Origin\' or
\'Aux Origin\' (Drill and Place offset)!"""
- msg+="""
Moreover in FC StepUP preferences you must have
\'PCB Settings\'->\'PCB Placement\'
set to \'Grid Origin\' or \'Aux Origin\'"""
+ msg = """To update 3D model Position(s) in an EXISTING KiCad pcb file
the KiCAD pcbnew board file must have assigned \'Grid Origin\' or
\'Aux Origin\' (Drill and Place offset)!"""
+ msg += """
Moreover in FC StepUP preferences you must have
\'PCB Settings\'->\'PCB Placement\'
set to \'Grid Origin\' or \'Aux Origin\'"""
say_warning(msg)
- msg="To update 3D model Position(s) in an EXISTING KiCad pcb file\nthe KiCAD pcbnew board file must have assigned \'Grid Origin\' or \'Aux Origin\' (Drill and Place offset)!"
- msg+="\nMoreover in FC StepUP preferences you must have\n\'PCB Settings\'->\'PCB Placement\'\nset to \'Grid Origin\' or \'Aux Origin\'"
+ msg = "To update 3D model Position(s) in an EXISTING KiCad pcb file\nthe KiCAD pcbnew board file must have assigned 'Grid Origin' or 'Aux Origin' (Drill and Place offset)!"
+ msg += "\nMoreover in FC StepUP preferences you must have\n'PCB Settings'->'PCB Placement'\nset to 'Grid Origin' or 'Aux Origin'"
sayerr(msg)
else:
- msg="""Save to an EXISTING KiCad pcb file to update your 3D model position!"""
+ msg = """Save to an EXISTING KiCad pcb file to update your 3D model position!"""
say_warning(msg)
- msg="Save to an EXISTING KiCad pcb file to update your 3D model position!"
+ msg = "Save to an EXISTING KiCad pcb file to update your 3D model position!"
sayerr(msg)
else:
- msg="""Operation aborted!"""
+ msg = """Operation aborted!"""
sayerr(msg)
say_info(msg)
else:
- msg="""select only 3D model(s) moved to be updated/pushed to kicad board!
a Time Stamp is required!"""
+ msg = """select only 3D model(s) moved to be updated/pushed to kicad board!
a Time Stamp is required!"""
sayerr(msg)
say_warning(msg)
+
###
def getModelsData(mypcb):
- """ mypcb = KicadPCB.load(file_pcb) """
+ """mypcb = KicadPCB.load(file_pcb)"""
## NB use always float() to guarantee number not string!!!
- import fcad_parser
- from fcad_parser import KicadPCB,SexpList
- import kicad_parser
-
- warn=""
+
+ warn = ""
PCB_Models = []
- Edge_Cuts_lvl=44
- Top_lvl=0
- conv_offs=25.4
- if hasattr(mypcb, 'host'):
+ Edge_Cuts_lvl = 44
+ Top_lvl = 0
+ conv_offs = 25.4
+ if hasattr(mypcb, "host"):
print(mypcb.host)
- if hasattr(mypcb, 'version'):
+ if hasattr(mypcb, "version"):
version = float(mypcb.version)
if version <= 3:
QtGui.QApplication.restoreOverrideCursor()
- reply = QtGui.QMessageBox.information(None,"Error ...","... KICAD pcb version "+ str(version)+" not supported \r\n"+"\r\nplease open and save your board with the latest kicad version")
+ QtGui.QMessageBox.information(
+ None,
+ "Error ...",
+ "... KICAD pcb version "
+ + str(version)
+ + " not supported \r\n"
+ + "\r\nplease open and save your board with the latest kicad version",
+ )
stop
- if version>=4:
- Edge_Cuts_lvl=44
- Top_lvl=0
- conv_offs=1.0
+ if version >= 4:
+ Edge_Cuts_lvl = 44
+ Top_lvl = 0
+ conv_offs = 1.0
if version >= 20171114:
- conv_offs=25.4
-
- for lynbr in mypcb.layers: #getting layers name
+ conv_offs = 25.4
+
+ for lynbr in mypcb.layers: # getting layers name
if float(lynbr) == Top_lvl:
- LvlTopName=(mypcb.layers['{0}'.format(str(lynbr))][0])
+ LvlTopName = mypcb.layers[f"{str(lynbr)}"][0]
if float(lynbr) == Edge_Cuts_lvl:
- LvlEdgeName=(mypcb.layers['{0}'.format(str(lynbr))][0])
+ (mypcb.layers[f"{str(lynbr)}"][0])
- for m in mypcb.module: #parsing modules #check top/bottom for placing 3D models
- #print(m.tstamp);print(m.fp_text[0][1])
- #stop
- if len(m.at)==2:
- m_angle=0
- else:
- m_angle=m.at[2]
- m_at=[m.at[0],-m.at[1]] #y reversed
- virtual=0
- if hasattr(m, 'attr'):
- if 'virtual' in m.attr:
- #say('virtual module')
- virtual=1
+ for m in mypcb.module: # parsing modules #check top/bottom for placing 3D models
+ # print(m.tstamp);print(m.fp_text[0][1])
+ # stop
+ m_angle = 0 if len(m.at) == 2 else m.at[2]
+ [m.at[0], -m.at[1]] # y reversed
+ virtual = 0
+ if hasattr(m, "attr"):
+ if "virtual" in m.attr:
+ # say('virtual module')
+ virtual = 1
else:
- virtual=0
+ virtual = 0
m_x = float(m.at[0])
m_y = float(m.at[1]) * (-1)
m_rot = float(m_angle)
- #sayw(m.layer);sayerr(LvlTopName)
+ # sayw(m.layer);sayerr(LvlTopName)
if m.layer == LvlTopName: # top
side = "Top"
- #sayw('top ' + m.layer)
+ # sayw('top ' + m.layer)
else:
side = "Bottom"
- m_rot *= -1 ##bottom 3d model rotation
- #sayw('bot ' + m.layer)
- n_md=1
+ m_rot *= -1 ##bottom 3d model rotation
+ # sayw('bot ' + m.layer)
+ n_md = 1
for md in m.model:
- #say (md[0]) #model name
- #say(md.at.xyz)
- #say(md.scale.xyz)
- #say(md.rotate.xyz)
- error_scale_module=False
- #say('scale ');sayw(scale_vrml)#;
- #error_scale_module=False
- xsc_vrml_val=md.scale.xyz[0]
- ysc_vrml_val=md.scale.xyz[1]
- zsc_vrml_val=md.scale.xyz[2]
+ # say (md[0]) #model name
+ # say(md.at.xyz)
+ # say(md.scale.xyz)
+ # say(md.rotate.xyz)
+ error_scale_module = False
+ # say('scale ');sayw(scale_vrml)#;
+ # error_scale_module=False
+ xsc_vrml_val = md.scale.xyz[0]
+ ysc_vrml_val = md.scale.xyz[1]
+ zsc_vrml_val = md.scale.xyz[2]
# if scale_vrml!='1 1 1':
- if float(xsc_vrml_val)!=1 or float(ysc_vrml_val)!=1 or float(zsc_vrml_val)!=1:
+ if float(xsc_vrml_val) != 1 or float(ysc_vrml_val) != 1 or float(zsc_vrml_val) != 1:
if "box_mcad" not in md[0] and "cylV_mcad" not in md[0] and "cylH_mcad" not in md[0]:
- sayw('wrong scale!!! set scale to (1 1 1)')
- error_scale_module=True
- #model_list.append(mdl_name[0])
- #model=model_list[j]+'.wrl'
- #if py2:
- if sys.version_info[0] == 2: #py2
- model=md[0].decode("utf-8")
- #stop
- else: #py3
- model=md[0] # py3 .decode("utf-8")
- #print (model, ' MODEL', type(model)) #maui test py3
- if (virtual==1 and addVirtual==0):
- model_name='no3Dmodel'
- side='noLayer'
+ sayw("wrong scale!!! set scale to (1 1 1)")
+ error_scale_module = True
+ # model_list.append(mdl_name[0])
+ # model=model_list[j]+'.wrl'
+ # if py2:
+ model = md[0] # py3 .decode("utf-8")
+ # print (model, ' MODEL', type(model)) #maui test py3
+ if virtual == 1 and addVirtual == 0:
+ model_name = "no3Dmodel"
+ side = "noLayer"
if model:
- sayw("virtual model "+model+" skipped") #virtual found warning
+ sayw("virtual model " + model + " skipped") # virtual found warning
else:
if model:
- model_name=model
- #sayw(model_name)
- warn=""
+ model_name = model
+ # sayw(model_name)
+ warn = ""
if "box_mcad" not in model_name and "cylV_mcad" not in model_name and "cylH_mcad" not in model_name:
if error_scale_module:
- sayw('wrong scale!!! for '+model_name+' Set scale to (1 1 1)')
- msg="""Error in '.kicad_pcb' model footprint
"""
- msg+="
reset values of
"+model_name+"
to:
"
- msg+="(scale (xyz 1 1 1))
"
- #warn+=("reset values of scale to (xyz 1 1 1)")
- warn=("reset values of scale to (xyz 1 1 1)")
+ sayw("wrong scale!!! for " + model_name + " Set scale to (1 1 1)")
+ msg = """Error in '.kicad_pcb' model footprint
"""
+ msg += "
reset values of
" + model_name + "
to:
"
+ msg += "(scale (xyz 1 1 1))
"
+ # warn+=("reset values of scale to (xyz 1 1 1)")
+ warn = "reset values of scale to (xyz 1 1 1)"
##reply = QtGui.QMessageBox.information(None,"info", msg)
- #stop
- #model_name=model_name[1:]
- #say(model_name)
- #sayw("here")
+ # stop
+ # model_name=model_name[1:]
+ # say(model_name)
+ # sayw("here")
else:
- model_name='no3Dmodel' #to do how to manage no3Dmodel
- side='noLayer'
- sayerr('no3Dmodel')
- mdl_name=model_name # re.findall(r'(.+?)\.wrl',params)
- #if virtual == 1:
+ model_name = "no3Dmodel" # to do how to manage no3Dmodel
+ side = "noLayer"
+ sayerr("no3Dmodel")
+ mdl_name = model_name # re.findall(r'(.+?)\.wrl',params)
+ # if virtual == 1:
# sayerr("virtual model(s)");sayw(mdl_name)
# sayw(mdl_name)
# sayerr(params)
if len(mdl_name) > 0:
# model_name, rot_comb, warn, pos_vrml, rotz_vrml, scale_vrml = get3DParams(mdl_name,params, rot, virtual)
- #sayerr(md.at.xyz)
- if conv_offs != 1: #pcb version >= 20171114 (offset wrl in mm)
- if hasattr(md,'at'):
- ofs=[md.at.xyz[0]/conv_offs,md.at.xyz[1]/conv_offs,md.at.xyz[2]/conv_offs]
- if hasattr(md,'offset'):
- ofs=[md.offset.xyz[0]/conv_offs,md.offset.xyz[1]/conv_offs,md.offset.xyz[2]/conv_offs]
+ # sayerr(md.at.xyz)
+ if conv_offs != 1: # pcb version >= 20171114 (offset wrl in mm)
+ if hasattr(md, "at"):
+ ofs = [md.at.xyz[0] / conv_offs, md.at.xyz[1] / conv_offs, md.at.xyz[2] / conv_offs]
+ if hasattr(md, "offset"):
+ ofs = [
+ md.offset.xyz[0] / conv_offs,
+ md.offset.xyz[1] / conv_offs,
+ md.offset.xyz[2] / conv_offs,
+ ]
else:
- ofs=md.at.xyz
+ ofs = md.at.xyz
line = []
line.append(model_name)
line.append(m_x)
line.append(m_y)
- line.append(m_rot-md.rotate.xyz[2])
+ line.append(m_rot - md.rotate.xyz[2])
line.append(side)
line.append(warn)
- line.append(ofs) #(md.at.xyz) #pos_vrml)
- line.append(md.rotate.xyz) #rotz_vrml)
- #sayerr(rotz_vrml)
- line.append(md.scale.xyz) #scale_vrml)
+ line.append(ofs) # (md.at.xyz) #pos_vrml)
+ line.append(md.rotate.xyz) # rotz_vrml)
+ # sayerr(rotz_vrml)
+ line.append(md.scale.xyz) # scale_vrml)
line.append(virtual)
- if hasattr(m,'tstamp'):
- line.append(m.tstamp) # fp tstamp
- elif hasattr(m,'uuid'):
- line.append(m.uuid) # fp tstamp
+ if hasattr(m, "tstamp"):
+ line.append(m.tstamp) # fp tstamp
+ elif hasattr(m, "uuid"):
+ line.append(m.uuid) # fp tstamp
else:
- sayw('missing \'TimeStamp\'')
- line.append('null')
+ sayw("missing 'TimeStamp'")
+ line.append("null")
try:
- line.append(m.fp_text[0][1]) #fp reference
+ line.append(m.fp_text[0][1]) # fp reference
except:
- line.append(m.property[0][1]) #fp reference kv8
- line.append(n_md) #number of models in module
+ line.append(m.property[0][1]) # fp reference kv8
+ line.append(n_md) # number of models in module
PCB_Models.append(line)
- n_md+=1
+ n_md += 1
return PCB_Models
+
+
###
+
def PullMoved():
global last_3d_path, start_time
global last_fp_path, test_flag
@@ -16607,237 +17888,242 @@ def PullMoved():
global pcb_path, use_AppPart, force_oldGroups, use_Links, use_LinkGroups
global original_filename, aux_orig, grid_orig
global off_x, off_y, maxRadius, use_pypro
-
- import fcad_parser
- from fcad_parser import KicadPCB,SexpList
- import kicad_parser
-
+
## to export to STEP an object and its links with a different placement and label
## two options must be set: 1) disable 'Reduce number of objects'; 2) disable 'Ignore instance names'
## NB the second one is not good for collaboration with different cads
-
- #say("export3DSTEP")
- if load_sketch==False:
- msg="""Board editing NOT supported on FC0.15!
please upgrade your FC release"""
+
+ # say("export3DSTEP")
+ if not load_sketch:
+ msg = """Board editing NOT supported on FC0.15!
please upgrade your FC release"""
say_warning(msg)
- msg="Board editing NOT supported on FC0.15!"
- sayerr(msg)
+ msg = "Board editing NOT supported on FC0.15!"
+ sayerr(msg)
else:
- check_ok=False
+ check_ok = False
sel = FreeCADGui.Selection.getSelection()
- if len (sel) >= 1:
+ if len(sel) >= 1:
for s in sel:
- if s.Label.rfind('_') < s.Label.rfind('['):
- ts = s.Label[s.Label.rfind('_')+1:s.Label.rfind('[')]
+ if s.Label.rfind("_") < s.Label.rfind("["):
+ ts = s.Label[s.Label.rfind("_") + 1 : s.Label.rfind("[")]
else:
- ts = s.Label[s.Label.rfind('_')+1:]
- if len (ts) == 8 or len (ts) == 12:
- #print(ts);stop
- check_ok=True
- #stop
+ ts = s.Label[s.Label.rfind("_") + 1 :]
+ if len(ts) == 8 or len(ts) == 12:
+ # print(ts);stop
+ check_ok = True
+ # stop
break
- #else:
+ # else:
# msg="""select only 3D model(s) moved to be updated/pushed to kicad board!
a TimeSTamp is required!"""
# sayerr(msg)
# say_warning(msg)
if check_ok:
cfg_read_all()
- #pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- #pg.GetString("last_3d_path")
+ # pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
+ # pg.GetString("last_3d_path")
if len(last_pcb_path) == 0:
- last_pcb_path=u''
- #sayw(last_pcb_path)
- #getSaveFileName(self,"saveFlle","Result.txt",filter ="txt (*.txt *.)")
- testing=False #True
+ last_pcb_path = ""
+ # sayw(last_pcb_path)
+ # getSaveFileName(self,"saveFlle","Result.txt",filter ="txt (*.txt *.)")
+ testing = False # True
if not testing:
- Filter=""
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if not(prefs_.GetBool('not_native_dlg')):
- fname, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Pull 3D model position(s) from pcbnew File...",
- make_unicode(last_pcb_path), "*.kicad_pcb")
+ if not (prefs_.GetBool("not_native_dlg")):
+ fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Pull 3D model position(s) from pcbnew File...",
+ make_unicode(last_pcb_path),
+ "*.kicad_pcb",
+ )
else:
- fname, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Pull 3D model position(s) from pcbnew File...",
- make_unicode(last_pcb_path), "*.kicad_pcb",options=QtWidgets.QFileDialog.DontUseNativeDialog)
+ fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Pull 3D model position(s) from pcbnew File...",
+ make_unicode(last_pcb_path),
+ "*.kicad_pcb",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
else:
- fname='c:/Temp/demo/test-rot.kicad_pcb'
+ fname = "c:/Temp/demo/test-rot.kicad_pcb"
if fname:
if os.path.exists(fname):
- last_3d_path=os.path.dirname(fname)
+ last_3d_path = os.path.dirname(fname)
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- pg.SetString("last_3d_path",make_string(last_3d_path))
- start_time=current_milli_time()
- doc=FreeCAD.ActiveDocument
- #filePath=last_pcb_path
- #fpath=filePath+os.sep+doc.Label+'.kicad_pcb'
- #sayerr('to '+fpath)
- #print fname
- if fname is None:
- fpath=original_filename
- else:
- fpath=fname
- sayerr('loading from '+fpath)
- #stop
+ pg.SetString("last_3d_path", make_string(last_3d_path))
+ start_time = current_milli_time()
+ # filePath=last_pcb_path
+ # fpath=filePath+os.sep+doc.Label+'.kicad_pcb'
+ # sayerr('to '+fpath)
+ # print fname
+ fpath = original_filename if fname is None else fname
+ sayerr("loading from " + fpath)
+ # stop
if len(fpath) > 0:
- #new_edge_list=getBoardOutline()
- #say (new_edge_list)
+ # new_edge_list=getBoardOutline()
+ # say (new_edge_list)
cfg_read_all()
- path, fname = os.path.split(fpath)
- name=os.path.splitext(fname)[0]
- ext=os.path.splitext(fname)[1]
+ _path, fname = os.path.split(fpath)
+ os.path.splitext(fname)[0]
+ os.path.splitext(fname)[1]
fpth = os.path.dirname(os.path.abspath(fpath))
- #filePath = os.path.split(os.path.realpath(__file__))[0]
- say ('my file path '+fpth)
+ # filePath = os.path.split(os.path.realpath(__file__))[0]
+ say("my file path " + fpth)
# stop
if fpth == "":
fpth = "."
last_pcb_path = fpth
last_pcb_path = re.sub("\\\\", "/", last_pcb_path)
ini_vars[10] = last_pcb_path
- #cfg_update_all()
+ # cfg_update_all()
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
pg.SetString("last_pcb_path", make_string(last_pcb_path))
- #sayerr(name+':'+ext)
+ # sayerr(name+':'+ext)
mypcb = KicadPCB.load(fpath)
mymodels = getModelsData(mypcb)
- pcbThickness=float(mypcb.general.thickness)
- #print(mymodels)
- #stop
- #with codecs.open(fpath,'r', encoding='utf-8') as txtFile:
+ pcbThickness = float(mypcb.general.thickness)
+ # print(mymodels)
+ # stop
+ # with codecs.open(fpath,'r', encoding='utf-8') as txtFile:
# content = txtFile.readlines() # problems?
- #content.append(u" ")
- #txtFile.close()
- #data=u''.join(content)
- #oft=None
- #if aux_orig == 1:
+ # content.append(u" ")
+ # txtFile.close()
+ # data=u''.join(content)
+ # oft=None
+ # if aux_orig == 1:
# oft=getAuxOrigin(data)
- #if grid_orig == 1:
+ # if grid_orig == 1:
# oft=getGridOrigin(data)
- #print oft
- #gof=False
- #if oft is not None:
+ # print oft
+ # gof=False
+ # if oft is not None:
# off_x=oft[0];off_y=-oft[1]
# offset = oft
# gof=True
# pcb_pull=True
- #else:
+ # else:
# pcb_pull=False
- oft=None
+ oft = None
if aux_orig == 1:
- if hasattr(mypcb, 'setup'):
- if hasattr(mypcb.setup, 'aux_axis_origin'):
- oft = mypcb.setup.aux_axis_origin
- #oft=getAuxOrigin(data)
+ if hasattr(mypcb, "setup"):
+ if hasattr(mypcb.setup, "aux_axis_origin"):
+ oft = mypcb.setup.aux_axis_origin
+ # oft=getAuxOrigin(data)
else:
- oft = [0.0,0.0]
+ oft = [0.0, 0.0]
elif grid_orig == 1:
- if hasattr(mypcb, 'setup'):
- if hasattr(mypcb.setup, 'grid_origin'):
- oft=mypcb.setup.grid_origin
- else:
- oft = [0.0,0.0]
+ if hasattr(mypcb, "setup"):
+ oft = mypcb.setup.grid_origin if hasattr(mypcb.setup, "grid_origin") else [0.0, 0.0]
else:
- oft = [0.0,0.0]
- #oft=getGridOrigin(data)
- #print ('oft ',oft)
- gof=False
-
- origin_warn=False
+ oft = [0.0, 0.0]
+ # oft=getGridOrigin(data)
+ # print ('oft ',oft)
+ gof = False
+
+ origin_warn = False
if oft is not None:
- if oft == [0.0,0.0]:
- origin_warn=True
- off_x=oft[0];off_y=-oft[1]
- offset = oft
- gof=True
- pcb_pull=True
+ if oft == [0.0, 0.0]:
+ origin_warn = True
+ off_x = oft[0]
+ off_y = -oft[1]
+ gof = True
+ pcb_pull = True
else:
- pcb_pull=False
- #print ('ofx,ofy reviewed ',off_x,' ',off_y)
- testing=False #True
+ pcb_pull = False
+ # print ('ofx,ofy reviewed ',off_x,' ',off_y)
+ testing = False # True
if pcb_pull:
for s in sel:
- #sayw(doc.Name)
- if 0: # use_pypro:
- if hasattr(s,"TimeStamp"):
- ts=s.TimeStamp
- content = push3D2pcb(s,content,ts,pcbThickness)
+ # sayw(doc.Name)
+ if 0: # use_pypro:
+ if hasattr(s, "TimeStamp"):
+ ts = s.TimeStamp
+ push3D2pcb(s, content, ts, pcbThickness)
else:
- msg="""select only 3D model(s) to be updated/pulled from kicad board!"""
+ msg = """select only 3D model(s) to be updated/pulled from kicad board!"""
sayerr(msg)
say_warning(msg)
else:
- if s.Label.rfind('_') < s.Label.rfind('['):
- ts = s.Label[s.Label.rfind('_')+1:s.Label.rfind('[')]
+ if s.Label.rfind("_") < s.Label.rfind("["):
+ ts = s.Label[s.Label.rfind("_") + 1 : s.Label.rfind("[")]
else:
- ts = s.Label[s.Label.rfind('_')+1:]
- if len (ts) == 8 or len (ts) == 12:
- #print (s.Label) #;stop
+ ts = s.Label[s.Label.rfind("_") + 1 :]
+ if len(ts) == 8 or len(ts) == 12:
+ # print (s.Label) #;stop
nbrModel = None
- if s.Label.rfind('_') < s.Label.rfind('['):
- #ts = s.Label[s.Label.rfind('_')+1:s.Label.rfind('[')]
- nbrModel = s.Label[s.Label.rfind('['):]
- #print(nbrModel)
- nMd = int(nbrModel.replace('[','').replace(']',''))-1
+ if s.Label.rfind("_") < s.Label.rfind("["):
+ # ts = s.Label[s.Label.rfind('_')+1:s.Label.rfind('[')]
+ nbrModel = s.Label[s.Label.rfind("[") :]
+ # print(nbrModel)
+ nMd = int(nbrModel.replace("[", "").replace("]", "")) - 1
else:
- #ts = s.Label[s.Label.rfind('_')+1:]
+ # ts = s.Label[s.Label.rfind('_')+1:]
nMd = 0
- #print('nbrModel = 0')
- #print('timestamp',ts,'numModel',nMd)
- content = pull3D2dsn(s,mymodels,ts,nMd,gof,pcbThickness)
- #else:
+ # print('nbrModel = 0')
+ # print('timestamp',ts,'numModel',nMd)
+ pull3D2dsn(s, mymodels, ts, nMd, gof, pcbThickness)
+ # else:
# msg="""select only 3D model(s) to be updated/pulled from kicad board!
a TimeSTamp is required!"""
# sayerr(msg)
# say_warning(msg)
say_time()
- msg="""3D model new position pulled from kicad board!
"""
- msg+="file loaded from
"+fpath+"
"
- msgr="3D model new position pulled from kicad board!\n"
+ msg = """3D model new position pulled from kicad board!
"""
+ msg += "file loaded from
" + fpath + "
"
+ msgr = "3D model new position pulled from kicad board!\n"
say(msgr)
say_info(msg)
if origin_warn:
if aux_orig == 1:
- origin_msg='AuxOrigin'
+ origin_msg = "AuxOrigin"
elif grid_orig == 1:
- origin_msg='GridOrigin'
- msg = origin_msg +' is set in FC Preferences but not set in KiCAD pcbnew file'
+ origin_msg = "GridOrigin"
+ msg = origin_msg + " is set in FC Preferences but not set in KiCAD pcbnew file"
sayw(msg)
- msg=""""""+origin_msg+""" is set in FreeCAD Preferences
but not set in KiCAD pcbnew file"""
- msg+="""
Please assign """+origin_msg+""" to your KiCAD pcbnew board file"""
- msg+="""
for a better Mechanical integration"""
+ msg = (
+ """"""
+ + origin_msg
+ + """ is set in FreeCAD Preferences
but not set in KiCAD pcbnew file"""
+ )
+ msg += """
Please assign """ + origin_msg + """ to your KiCAD pcbnew board file"""
+ msg += """
for a better Mechanical integration"""
say_warning(msg)
else:
- msg="""To update 3D model Position(s) from an EXISTING KiCad pcb file
the KiCAD pcbnew board file must have assigned \'Grid Origin\' or
\'Aux Origin\' (Drill and Place offset)!"""
- msg+="""
Moreover in FC StepUP preferences you must have
\'PCB Settings\'->\'PCB Placement\'
set to \'Grid Origin\' or \'Aux Origin\'"""
+ msg = """To update 3D model Position(s) from an EXISTING KiCad pcb file
the KiCAD pcbnew board file must have assigned \'Grid Origin\' or
\'Aux Origin\' (Drill and Place offset)!"""
+ msg += """
Moreover in FC StepUP preferences you must have
\'PCB Settings\'->\'PCB Placement\'
set to \'Grid Origin\' or \'Aux Origin\'"""
say_warning(msg)
- msg="To update 3D model Position(s) from an EXISTING KiCad pcb file\nthe KiCAD pcbnew board file must have assigned \'Grid Origin\' or \'Aux Origin\' (Drill and Place offset)!"
- msg+="\nMoreover in FC StepUP preferences you must have \n\'PCB Settings\'->\'PCB Placement\'\nset to \'Grid Origin\' or \'Aux Origin\'"
+ msg = "To update 3D model Position(s) from an EXISTING KiCad pcb file\nthe KiCAD pcbnew board file must have assigned 'Grid Origin' or 'Aux Origin' (Drill and Place offset)!"
+ msg += "\nMoreover in FC StepUP preferences you must have \n'PCB Settings'->'PCB Placement'\nset to 'Grid Origin' or 'Aux Origin'"
sayerr(msg)
else:
- msg="""Load from an EXISTING KiCad pcb file to update your 3D model position!"""
+ msg = """Load from an EXISTING KiCad pcb file to update your 3D model position!"""
say_warning(msg)
- msg="Load from an EXISTING KiCad pcb file to update your 3D model position!"
+ msg = "Load from an EXISTING KiCad pcb file to update your 3D model position!"
sayerr(msg)
else:
- msg="""Operation aborted!"""
+ msg = """Operation aborted!"""
sayerr(msg)
say_info(msg)
else:
- msg="""select only 3D model(s) to be updated/pulled from kicad board!
a Time Stamp is required!"""
+ msg = (
+ """select only 3D model(s) to be updated/pulled from kicad board!
a Time Stamp is required!"""
+ )
sayerr(msg)
say_warning(msg)
+
##
+
def PushFootprint():
-#def onExport3DStep(self):
+ # def onExport3DStep(self):
global last_3d_path, start_time, load_sketch, last_pcb_path
- #say("export3DSTEP")
- if load_sketch==False:
- msg="""Edge editing NOT supported on FC0.15!
please upgrade your FC release"""
+ # say("export3DSTEP")
+ if not load_sketch:
+ msg = """Edge editing NOT supported on FC0.15!
please upgrade your FC release"""
say_warning(msg)
- msg="Edge editing NOT supported on FC0.15!"
- sayerr(msg)
- #if 0:
- #if FreeCAD.ActiveDocument is None:
+ msg = "Edge editing NOT supported on FC0.15!"
+ sayerr(msg)
+ # if 0:
+ # if FreeCAD.ActiveDocument is None:
# FreeCAD.newDocument("PCB_Sketch")
# PCB_Sketch= FreeCAD.activeDocument().addObject('Sketcher::SketchObject','PCB_Sketch')
# offset=[0.0,0.0] #offset=[148.5,98.5]
@@ -16846,183 +18132,204 @@ def PushFootprint():
# FreeCADGui.SendMsgToActiveView("ViewFit")
else:
sel = FreeCADGui.Selection.getSelection()
- if len (sel) >= 1:
- #sayw(doc.Name)
- to_discretize=False;sk_to_discr=[];sk_temp=[];sk_to_convert=[];sk_to_reselect=[]
- fp_label=u''
- #annular=0.125
+ if len(sel) >= 1:
+ # sayw(doc.Name)
+ to_discretize = False
+ sk_to_discr = []
+ sk_temp = []
+ sk_to_convert = []
+ sk_to_reselect = []
+ fp_label = ""
+ # annular=0.125
if "Sketch" in sel[0].TypeId or "Group" in sel[0].TypeId:
if "Group" in sel[0].TypeId:
- #print(FreeCAD.ActiveDocument.getObject(sel[0].Name).OutList,'g.OutList')
- #for o in FreeCAD.ActiveDocument.Objects:
- #print((sel[0].Name))
- fp_label=sel[0].Label.replace(' ','_')
+ # print(FreeCAD.ActiveDocument.getObject(sel[0].Name).OutList,'g.OutList')
+ # for o in FreeCAD.ActiveDocument.Objects:
+ # print((sel[0].Name))
+ fp_label = sel[0].Label.replace(" ", "_")
for o in FreeCAD.ActiveDocument.getObject(sel[0].Name).OutList:
- #if sel[0] in o.InList:
- #print(o.Label)
- if 'PTH_Drills' in o.Label:
- centers=[];rads=[]
- for idx,g in enumerate(o.Geometry):
- #if 'ArcOfCircle' in str(g) and not isConstruction(g): #o.getConstruction(idx): #g.Construction:
- if 'Circle' in str(g) and isConstruction(g) == False:
+ # if sel[0] in o.InList:
+ # print(o.Label)
+ if "PTH_Drills" in o.Label:
+ centers = []
+ rads = []
+ for idx, g in enumerate(o.Geometry):
+ # if 'ArcOfCircle' in str(g) and not isConstruction(g): #o.getConstruction(idx): #g.Construction:
+ if "Circle" in str(g) and not isConstruction(g):
if not (g.Center in centers and g.Radius in rads):
- centers.append(g.Center);rads.append(g.Radius)
- #print(len(centers), centers)
- if 'NPTH_Drills' not in o.Label:
- if '_padNbr=' in o.Label:
- skLabel = 'Sketch_Pads_TH_SMD'+o.Label[o.Label.index('_padNbr='):]+'_tmp'
- elif '_padNum=' in o.Label:
- skLabel = 'Sketch_Pads_TH_SMD'+o.Label[o.Label.index('_padNum='):]+'_tmp'
+ centers.append(g.Center)
+ rads.append(g.Radius)
+ # print(len(centers), centers)
+ if "NPTH_Drills" not in o.Label:
+ if "_padNbr=" in o.Label:
+ skLabel = "Sketch_Pads_TH_SMD" + o.Label[o.Label.index("_padNbr=") :] + "_tmp"
+ elif "_padNum=" in o.Label:
+ skLabel = "Sketch_Pads_TH_SMD" + o.Label[o.Label.index("_padNum=") :] + "_tmp"
else:
- skLabel = 'Sketch_Pads_TH_SMD_tmp'
+ skLabel = "Sketch_Pads_TH_SMD_tmp"
else:
- skLabel = 'Sketch_Pads_NPTH_tmp'
- FreeCAD.ActiveDocument.addObject('Sketcher::SketchObject', skLabel)
- skd_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.ActiveObject.Label = skLabel #workaround to keep '=' in Label
+ skLabel = "Sketch_Pads_NPTH_tmp"
+ FreeCAD.ActiveDocument.addObject("Sketcher::SketchObject", skLabel)
+ skd_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.ActiveObject.Label = skLabel # workaround to keep '=' in Label
sk_temp.append(FreeCAD.ActiveDocument.ActiveObject)
- #FreeCAD.ActiveDocument.getObject(skd_name).Placement = FreeCAD.Placement(FreeCAD.Vector(0.000000, 0.000000, 0.000000), FreeCAD.Rotation(0.000000, 0.000000, 0.000000, 1.000000))
- #FreeCAD.ActiveDocument.getObject(skd_name).MapMode = "Deactivated"
- #print(centers)
- for i,c in enumerate(centers):
- FreeCAD.ActiveDocument.getObject(skd_name).addGeometry(Part.Circle(FreeCAD.Vector(c[0], c[1]), FreeCAD.Vector(0, 0, 1), rads[i]))
- if 'Pads_NPTH' not in FreeCAD.ActiveDocument.getObject(skd_name).Label:
- FreeCAD.ActiveDocument.getObject(skd_name).addGeometry(Part.Circle(FreeCAD.Vector(c[0], c[1]), FreeCAD.Vector(0, 0, 1), rads[i]*1.4)) # annular = 40% of radius
+ # FreeCAD.ActiveDocument.getObject(skd_name).Placement = FreeCAD.Placement(FreeCAD.Vector(0.000000, 0.000000, 0.000000), FreeCAD.Rotation(0.000000, 0.000000, 0.000000, 1.000000))
+ # FreeCAD.ActiveDocument.getObject(skd_name).MapMode = "Deactivated"
+ # print(centers)
+ for i, c in enumerate(centers):
+ FreeCAD.ActiveDocument.getObject(skd_name).addGeometry(
+ Part.Circle(FreeCAD.Vector(c[0], c[1]), FreeCAD.Vector(0, 0, 1), rads[i]),
+ )
+ if "Pads_NPTH" not in FreeCAD.ActiveDocument.getObject(skd_name).Label:
+ FreeCAD.ActiveDocument.getObject(skd_name).addGeometry(
+ Part.Circle(FreeCAD.Vector(c[0], c[1]), FreeCAD.Vector(0, 0, 1), rads[i] * 1.4),
+ ) # annular = 40% of radius
FreeCAD.ActiveDocument.recompute()
FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(skd_name))
sk_to_convert.append(FreeCAD.ActiveDocument.getObject(skd_name))
sk_to_reselect.append(o)
- if 'F_Silks' in o.Label or 'F_Fab' in o.Label or 'F_CrtYd' in o.Label \
- or 'Dwg' in o.Label or 'Cmts' in o.Label \
- or 'Pads_TH' in o.Label or 'Pads_NPTH' in o.Label or 'Edge_Cuts' in o.Label\
- or 'Pads_Round_Rect' in o.Label or 'FZ_' in o.Label\
- or 'Pads_Geom' in o.Label:
- #or 'Pads_Round_Rect' in o.Label or 'Pads_Poly' in o.Label or 'NetTie_Poly' in o.Label or 'FZ_' in o.Label\
- #print('adding selection ',o.Label)
+ if (
+ "F_Silks" in o.Label
+ or "F_Fab" in o.Label
+ or "F_CrtYd" in o.Label
+ or "Dwg" in o.Label
+ or "Cmts" in o.Label
+ or "Pads_TH" in o.Label
+ or "Pads_NPTH" in o.Label
+ or "Edge_Cuts" in o.Label
+ or "Pads_Round_Rect" in o.Label
+ or "FZ_" in o.Label
+ or "Pads_Geom" in o.Label
+ ):
+ # or 'Pads_Round_Rect' in o.Label or 'Pads_Poly' in o.Label or 'NetTie_Poly' in o.Label or 'FZ_' in o.Label\
+ # print('adding selection ',o.Label)
FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(o.Name))
sk_to_convert.append(o)
- #print(o.Label,'sk added')
- if hasattr(o,"LabelText"):
+ # print(o.Label,'sk added')
+ if hasattr(o, "LabelText"):
sayerr(o.LabelText)
- if 'Ref' in o.Label or 'Val' in o.Label:
+ if "Ref" in o.Label or "Val" in o.Label:
FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.getObject(o.Name))
sk_to_convert.append(o)
## checking Pads_Poly for ArcOfCircle to be discretized
- to_discretize=False
- if 'NetTie_Poly' in o.Label:
- if hasattr(o,"Geometry"):
- for g in o.Geometry:
- if 'ArcOfCircle' in str(g) and not isConstruction(g):
- FreeCAD.Console.PrintWarning('need to discretize Arcs\n')
- to_discretize=True
- if to_discretize:
- sk_to_discr.append(o)
- FreeCADGui.Selection.removeSelection(o)
- else:
- #print(o.Label,'sk added')
- sk_to_convert.append(o)
- to_discretize=False
- if 'Pads_Poly' in o.Label:
- if hasattr(o,"Geometry"):
- for g in o.Geometry:
- if 'ArcOfCircle' in str(g) and not isConstruction(g):
- FreeCAD.Console.PrintWarning('need to discretize Arcs\n')
- to_discretize=True
- if to_discretize:
- sk_to_discr.append(o)
- FreeCADGui.Selection.removeSelection(o)
- else:
- #print(o.Label,'sk added')
- sk_to_convert.append(o)
+ to_discretize = False
+ if "NetTie_Poly" in o.Label and hasattr(o, "Geometry"):
+ for g in o.Geometry:
+ if "ArcOfCircle" in str(g) and not isConstruction(g):
+ FreeCAD.Console.PrintWarning("need to discretize Arcs\n")
+ to_discretize = True
+ if to_discretize:
+ sk_to_discr.append(o)
+ FreeCADGui.Selection.removeSelection(o)
+ else:
+ # print(o.Label,'sk added')
+ sk_to_convert.append(o)
+ to_discretize = False
+ if "Pads_Poly" in o.Label and hasattr(o, "Geometry"):
+ for g in o.Geometry:
+ if "ArcOfCircle" in str(g) and not isConstruction(g):
+ FreeCAD.Console.PrintWarning("need to discretize Arcs\n")
+ to_discretize = True
+ if to_discretize:
+ sk_to_discr.append(o)
+ FreeCADGui.Selection.removeSelection(o)
+ else:
+ # print(o.Label,'sk added')
+ sk_to_convert.append(o)
else:
for o in sel:
- to_discretize=False
- if 'PTH_Drills' in o.Label:
- #o= sel[0]
- centers=[];rads=[]
- for idx,g in enumerate(o.Geometry):
- if 'Circle' in str(g) and not isConstruction(g):
+ to_discretize = False
+ if "PTH_Drills" in o.Label:
+ # o= sel[0]
+ centers = []
+ rads = []
+ for idx, g in enumerate(o.Geometry):
+ if "Circle" in str(g) and not isConstruction(g):
if not (g.Center in centers and g.Radius in rads):
- centers.append(g.Center);rads.append(g.Radius)
- #print(len(centers), centers)
- if 'NPTH_Drills' not in o.Label:
- if '_padNbr=' in o.Label:
- skLabel = 'Sketch_Pads_TH_SMD'+o.Label[o.Label.index('_padNbr='):]+'_tmp'
- elif '_padNum=' in o.Label:
- skLabel = 'Sketch_Pads_TH_SMD'+o.Label[o.Label.index('_padNum='):]+'_tmp'
+ centers.append(g.Center)
+ rads.append(g.Radius)
+ # print(len(centers), centers)
+ if "NPTH_Drills" not in o.Label:
+ if "_padNbr=" in o.Label:
+ skLabel = "Sketch_Pads_TH_SMD" + o.Label[o.Label.index("_padNbr=") :] + "_tmp"
+ elif "_padNum=" in o.Label:
+ skLabel = "Sketch_Pads_TH_SMD" + o.Label[o.Label.index("_padNum=") :] + "_tmp"
else:
- skLabel = 'Sketch_Pads_TH_SMD_tmp'
+ skLabel = "Sketch_Pads_TH_SMD_tmp"
else:
- skLabel = 'Sketch_Pads_NPTH_tmp'
- FreeCAD.ActiveDocument.addObject('Sketcher::SketchObject', skLabel)
- skd_name=FreeCAD.ActiveDocument.ActiveObject.Name
- FreeCAD.ActiveDocument.ActiveObject.Label = skLabel #workaround to keep '=' in Label
+ skLabel = "Sketch_Pads_NPTH_tmp"
+ FreeCAD.ActiveDocument.addObject("Sketcher::SketchObject", skLabel)
+ skd_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.ActiveObject.Label = skLabel # workaround to keep '=' in Label
sk_temp.append(FreeCAD.ActiveDocument.ActiveObject)
sk_to_convert.append(FreeCAD.ActiveDocument.ActiveObject)
FreeCADGui.Selection.removeSelection(o)
sk_to_reselect.append(o)
- #FreeCAD.ActiveDocument.getObject(skd_name).Placement = FreeCAD.Placement(FreeCAD.Vector(0.000000, 0.000000, 0.000000), FreeCAD.Rotation(0.000000, 0.000000, 0.000000, 1.000000))
- #FreeCAD.ActiveDocument.getObject(skd_name).MapMode = "Deactivated"
- for i,c in enumerate(centers):
- FreeCAD.ActiveDocument.getObject(skd_name).addGeometry(Part.Circle(FreeCAD.Vector(c[0], c[1]), FreeCAD.Vector(0, 0, 1), rads[i]))
- if 'NPTH_Drills' not in o.Label:
- FreeCAD.ActiveDocument.getObject(skd_name).addGeometry(Part.Circle(FreeCAD.Vector(c[0], c[1]), FreeCAD.Vector(0, 0, 1), rads[i]*1.4)) # annular = 40% of radius # +annular))
+ # FreeCAD.ActiveDocument.getObject(skd_name).Placement = FreeCAD.Placement(FreeCAD.Vector(0.000000, 0.000000, 0.000000), FreeCAD.Rotation(0.000000, 0.000000, 0.000000, 1.000000))
+ # FreeCAD.ActiveDocument.getObject(skd_name).MapMode = "Deactivated"
+ for i, c in enumerate(centers):
+ FreeCAD.ActiveDocument.getObject(skd_name).addGeometry(
+ Part.Circle(FreeCAD.Vector(c[0], c[1]), FreeCAD.Vector(0, 0, 1), rads[i]),
+ )
+ if "NPTH_Drills" not in o.Label:
+ FreeCAD.ActiveDocument.getObject(skd_name).addGeometry(
+ Part.Circle(FreeCAD.Vector(c[0], c[1]), FreeCAD.Vector(0, 0, 1), rads[i] * 1.4),
+ ) # annular = 40% of radius # +annular))
FreeCAD.ActiveDocument.recompute()
- elif 'NetTie_Poly' in o.Label:
+ elif "NetTie_Poly" in o.Label:
for g in sel[0].Geometry:
- if 'ArcOfCircle' in str(g):
- FreeCAD.Console.PrintWarning('need to discretize Arcs\n')
- to_discretize=True
+ if "ArcOfCircle" in str(g):
+ FreeCAD.Console.PrintWarning("need to discretize Arcs\n")
+ to_discretize = True
if to_discretize:
sk_to_discr.append(o)
FreeCADGui.Selection.removeSelection(o)
else:
- #print(o.Label,'sk added')
+ # print(o.Label,'sk added')
sk_to_convert.append(o)
- elif 'Pads_Poly' in o.Label:
- to_discretize=False
+ elif "Pads_Poly" in o.Label:
+ to_discretize = False
for g in o.Geometry:
- if 'ArcOfCircle' in str(g):
- FreeCAD.Console.PrintWarning('need to discretize Arcs\n')
- to_discretize=True
+ if "ArcOfCircle" in str(g):
+ FreeCAD.Console.PrintWarning("need to discretize Arcs\n")
+ to_discretize = True
if to_discretize:
sk_to_discr.append(o)
FreeCADGui.Selection.removeSelection(o)
else:
- print(o.Label,'sk added')
+ print(o.Label, "sk added")
sk_to_convert.append(o)
for sk in sk_to_discr:
- ws=sk.Shape.copy()
- #Part.show(ws)
- wn=[]
- q_deflection = 0.005 #0.02 ##0.005
- wnc=[]
+ ws = sk.Shape.copy()
+ # Part.show(ws)
+ wn = []
+ q_deflection = 0.005 # 0.02 ##0.005
+ wnc = []
for e in ws.Edges:
- if hasattr(e.Curve,'Radius'):
+ if hasattr(e.Curve, "Radius"):
if not e.Closed: # Arc and not Circle
wn.append(Part.makePolygon(e.discretize(QuasiDeflection=q_deflection)))
- sayw('added discretized arc')
+ sayw("added discretized arc")
else:
- #wn.append(Part.Wire(e))
+ # wn.append(Part.Wire(e))
wnc.append(Part.Wire(e))
- sayw('added circle pad')
+ sayw("added circle pad")
else:
wn.append(Part.Wire(e))
- #sk_d=Draft.makeSketch(wn)
- edgs=[]
+ # sk_d=Draft.makeSketch(wn)
+ edgs = []
for s in wn:
- for e in s.Edges:
- edgs.append(e)
+ edgs.extend(s.Edges)
# wns = Part.Wire(Part.__sortEdges__(edgs))
- #Part.show(wnc[0])
- #print (wns);print(wnc[0])
- if len(wnc)>0:
+ # Part.show(wnc[0])
+ # print (wns);print(wnc[0])
+ if len(wnc) > 0:
wns = Part.Wire(Part.__sortEdges__(edgs))
- sk_d=Draft.makeSketch([wns,wnc[0]], autoconstraints=True)
+ sk_d = Draft.makeSketch([wns, wnc[0]], autoconstraints=True)
else:
- sk_d=Draft.makeSketch(edgs, autoconstraints=True)
+ sk_d = Draft.makeSketch(edgs, autoconstraints=True)
Connect = sk_d
- #stop
+ # stop
# for e in ws.Edges:
# if hasattr(e.Curve,'Radius'):
# if not e.Closed: # Arc and not Circle
@@ -17045,17 +18352,17 @@ def PushFootprint():
# edgs.append(e)
# #print (e,e.TypeId)
# #wns = Part.Wire(Part.__sortEdges__(edgs))
-
- #lines = []
- #points = []
- #p_coords = []
- #for wire in wn:
+
+ # lines = []
+ # points = []
+ # p_coords = []
+ # for wire in wn:
# #points = []
# for vert in wire.Vertexes:
# points.append(vert.Point)
# p_coords.append((vert.Point.x,vert.Point.y))
- #print(points)
- #print(p_coords)
+ # print(points)
+ # print(p_coords)
# p=p_coords
# import functools
# import math
@@ -17087,282 +18394,298 @@ def PushFootprint():
## if len (wnc)>0:
## edgs.append(wnc[0].Edges[0])
## sk_d=Draft.makeSketch(edgs, autoconstraints=True)
-
+
## FreeCAD.ActiveDocument.recompute()
### creating an edge ordered sketch
- del_sk_d = True
if 0:
try:
### Begin command Part_CompJoinFeatures
- say('importing BOPTools')
- import PartGui
+ say("importing BOPTools")
# from PartGui import BOPTools
import BOPTools
import BOPTools.JoinFeatures
- say('trying makeConnect')
- j = BOPTools.JoinFeatures.makeConnect(name='Connect')
+
+ say("trying makeConnect")
+ j = BOPTools.JoinFeatures.makeConnect(name="Connect")
j.Objects = [sk_d]
j.Proxy.execute(j)
j.purgeTouched()
for obj in j.ViewObject.Proxy.claimChildren():
obj.ViewObject.hide()
### End command Part_CompJoinFeatures
- say('makeConnect done')
+ say("makeConnect done")
Connect = FreeCAD.ActiveDocument.ActiveObject
except:
- sayw('failed makeConnect')
+ sayw("failed makeConnect")
FreeCAD.ActiveDocument.removeObject(FreeCAD.ActiveDocument.ActiveObject.Name)
Connect = sk_d
- del_sk_d = False
- sv0 = Draft.makeShape2DView(FreeCAD.ActiveDocument.getObject(Connect.Name), FreeCAD.Vector(-0.0, -0.0, 1.0))
+ sv0 = Draft.makeShape2DView(
+ FreeCAD.ActiveDocument.getObject(Connect.Name),
+ FreeCAD.Vector(-0.0, -0.0, 1.0),
+ )
FreeCAD.ActiveDocument.recompute()
FreeCAD.ActiveDocument.removeObject(Connect.Name)
- if 0: #del_sk_d:
+ if 0: # del_sk_d:
FreeCAD.ActiveDocument.removeObject(sk_d.Name)
- #FreeCADGui.Selection.clearSelection()
- #FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Name,sv0.Name)
+ # FreeCADGui.Selection.clearSelection()
+ # FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Name,sv0.Name)
sk_d = Draft.makeSketch(FreeCAD.ActiveDocument.getObject(sv0.Name), autoconstraints=True)
FreeCAD.ActiveDocument.removeObject(sv0.Name)
FreeCAD.ActiveDocument.recompute()
- #stop
- #ws=sk_d.Shape.copy()
- #sk_do = Draft.makeSketch(ws)
- #Part.makePolygon(ws.Edges)
- #FreeCAD.ActiveDocument.removeObject(sk_d.Name)
- sk_d.Label=sk.Label+'_'
+ # stop
+ # ws=sk_d.Shape.copy()
+ # sk_do = Draft.makeSketch(ws)
+ # Part.makePolygon(ws.Edges)
+ # FreeCAD.ActiveDocument.removeObject(sk_d.Name)
+ sk_d.Label = sk.Label + "_"
FreeCADGui.Selection.addSelection(sk_d)
sk_to_convert.append(sk_d)
sk_temp.append(sk_d)
- #stop
+ # stop
FreeCAD.ActiveDocument.recompute()
- #stop
- #if "Group" in sel[0].TypeId:
+ # stop
+ # if "Group" in sel[0].TypeId:
# for o in FreeCAD.ActiveDocument.Objects:
# FreeCADGui.Selection.addSelection(o)
cfg_read_all()
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
last_fp_path = pg.GetString("last_fp_path")
if len(last_fp_path) == 0:
- last_fp_path=last_pcb_path
- #sayw(last_pcb_path)
- #getSaveFileName(self,"saveFlle","Result.txt",filter ="txt (*.txt *.)")
- testing=False #True
+ last_fp_path = last_pcb_path
+ # sayw(last_pcb_path)
+ # getSaveFileName(self,"saveFlle","Result.txt",filter ="txt (*.txt *.)")
+ testing = False # True
for s in sk_to_convert:
FreeCADGui.Selection.addSelection(s)
- #print(s.Label,'added')
+ # print(s.Label,'added')
for s in sk_to_discr:
FreeCADGui.Selection.removeSelection(s)
- #stop
+ # stop
if not testing:
- Filter=""
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if not(prefs_.GetBool('not_native_dlg')):
- name, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Push Footprint to KiCad module ...",
- make_unicode(last_fp_path), "*.kicad_mod")
+ if not (prefs_.GetBool("not_native_dlg")):
+ name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName(
+ None,
+ "Push Footprint to KiCad module ...",
+ make_unicode(last_fp_path),
+ "*.kicad_mod",
+ )
else:
- name, Filter = PySide.QtGui.QFileDialog.getSaveFileName(None, "Push Footprint to KiCad module ...",
- make_unicode(last_fp_path), "*.kicad_mod",options=QtWidgets.QFileDialog.DontUseNativeDialog)
- else:
- if os.path.isdir("d:/Temp/"):
- name='d:/Temp/ex2.kicad_mod'
- elif os.path.isdir("c:/Temp/"):
- name='c:/Temp/ex2.kicad_mod'
- #say(name)
+ name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName(
+ None,
+ "Push Footprint to KiCad module ...",
+ make_unicode(last_fp_path),
+ "*.kicad_mod",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
+ elif os.path.isdir("d:/Temp/"):
+ name = "d:/Temp/ex2.kicad_mod"
+ elif os.path.isdir("c:/Temp/"):
+ name = "c:/Temp/ex2.kicad_mod"
+ # say(name)
# stop
if name:
- #if os.path.exists(name):
- last_fp_path=os.path.dirname(name)
+ # if os.path.exists(name):
+ last_fp_path = os.path.dirname(name)
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- pg.SetString("last_fp_path", make_string(last_fp_path)) # py3 .decode("utf-8")
- start_time=current_milli_time()
- if not name.endswith('.kicad_mod'):
- name=name+u'.kicad_mod'
- export_footprint(name,fp_label)
+ pg.SetString("last_fp_path", make_string(last_fp_path)) # py3 .decode("utf-8")
+ start_time = current_milli_time()
+ if not name.endswith(".kicad_mod"):
+ name = name + ".kicad_mod"
+ export_footprint(name, fp_label)
for s in sk_to_discr:
FreeCADGui.Selection.addSelection(s)
for s in sk_to_reselect:
FreeCADGui.Selection.addSelection(s)
- #stop
+ # stop
if not testing:
for s in sk_temp:
FreeCAD.ActiveDocument.removeObject(s.Name)
- #else:
+ # else:
# msg="""Save to an EXISTING KiCad pcb file to update your Edge!"""
# say_warning(msg)
# msg="Save to an EXISTING KiCad pcb file to update your Edge!"
# sayerr(msg)
- #elif 'Shape2DView' in sel[0].Name: #TBD Shape2DView to fp
+ # elif 'Shape2DView' in sel[0].Name: #TBD Shape2DView to fp
# if 'F_Silks' in o.Label or 'F_Fab' in o.Label or 'F_CrtYd' in o.Label \
# or 'Dwg' in o.Label or 'Cmts' in o.Label:
else:
- msg="""Select Group or Sketch/Text elements to be converted to KiCad Footprint!"""
+ msg = """Select Group or Sketch/Text elements to be converted to KiCad Footprint!"""
sayerr(msg)
say_warning(msg)
else:
- msg="""Select Group or Sketch/Text elements to be converted to KiCad Footprint!"""
+ msg = """Select Group or Sketch/Text elements to be converted to KiCad Footprint!"""
sayerr(msg)
say_warning(msg)
+
+
###
+
def simplify_sketch_old():
- ''' simplifying & sanitizing sketches '''
+ """simplifying & sanitizing sketches"""
global maxRadius, edge_tolerance
-
+
doc = FreeCAD.ActiveDocument
sel = FreeCADGui.Selection.getSelection()
- if len(sel)==1:
- if 'Sketcher' in sel[0].TypeId:
+ if len(sel) == 1:
+ if "Sketcher" in sel[0].TypeId:
sanitizeSketch(sel[0].Name)
- new_edge_list, not_supported, to_discretize, construction_geom = getBoardOutline()
+ new_edge_list, _not_supported, to_discretize, _construction_geom = getBoardOutline()
## support for arcs, lines and bsplines in F_Silks
sel = FreeCADGui.Selection.getSelection()
- sk_name=None
- sk_name=sel[0].Name
- sk_label=sel[0].Label
- if len(to_discretize)>0 and sk_name is not None:
- FreeCADGui.ActiveDocument.getObject(sk_name).Visibility=False # hidden Sketch
- #sel = FreeCADGui.Selection.getSelection()
- #for s in sel:
+ sk_name = None
+ sk_name = sel[0].Name
+ sk_label = sel[0].Label
+ if len(to_discretize) > 0 and sk_name is not None:
+ FreeCADGui.ActiveDocument.getObject(sk_name).Visibility = False # hidden Sketch
+ # sel = FreeCADGui.Selection.getSelection()
+ # for s in sel:
# if 'F_Silks' in s.Label:
# sk_name=s.Name
- #if len (sel)==1:
- #sk_name=sel[0].Name
- t_name=cpy_sketch(sk_name)
+ # if len (sel)==1:
+ # sk_name=sel[0].Name
+ t_name = cpy_sketch(sk_name)
###t_sk=FreeCAD.ActiveDocument.copyObject(FreeCAD.ActiveDocument.getObject(sk_name))
- elist, to_dis=check_geom(t_name)
- #Draft.clone(FreeCAD.ActiveDocument.getObject(sk_name),copy=True)
- #clone_name=App.ActiveDocument.ActiveObject.Name
- geoBasic=[]
- geoBasic=split_basic_geom(t_name, to_dis)
- #print geoBasic
- #remove_basic_geom(t_name, to_dis)
+ elist, to_dis = check_geom(t_name)
+ # Draft.clone(FreeCAD.ActiveDocument.getObject(sk_name),copy=True)
+ # clone_name=App.ActiveDocument.ActiveObject.Name
+ geoBasic = []
+ geoBasic = split_basic_geom(t_name, to_dis)
+ # print geoBasic
+ # remove_basic_geom(t_name, to_dis)
## remove_basic_geom(t_name, to_dis)
##remove_basic_geom(t_sk.Name, to_discretize)
##elist, to_dis=check_geom(t_sk.Name)
- #print elist
- #stop
- obj_list_prev=[]
+ # print elist
+ # stop
+ obj_list_prev = []
for obj in doc.Objects:
- #print obj.TypeId
- if (obj.TypeId=="Part::Feature") or (obj.TypeId=="Sketcher::SketchObject"):
+ # print obj.TypeId
+ if obj.TypeId in {"Part::Feature", "Sketcher::SketchObject"}:
obj_list_prev.append(obj.Name)
- #Draft.draftify(FreeCAD.ActiveDocument.getObject(t_name),delete=True)
- #Draft.draftify(FreeCAD.ActiveDocument.getObject(t_name),delete=False)
- b=FreeCAD.ActiveDocument.getObject(t_name)
- shp1=b.Shape.copy()
+ # Draft.draftify(FreeCAD.ActiveDocument.getObject(t_name),delete=True)
+ # Draft.draftify(FreeCAD.ActiveDocument.getObject(t_name),delete=False)
+ b = FreeCAD.ActiveDocument.getObject(t_name)
+ shp1 = b.Shape.copy()
Part.show(shp1)
FreeCAD.ActiveDocument.removeObject(t_name)
FreeCAD.ActiveDocument.recompute()
- #stop
- obj_list_after=[]
+ # stop
+ obj_list_after = []
for obj in doc.Objects:
- if (obj.TypeId=="Part::Feature") or (obj.TypeId=="Sketcher::SketchObject")\
- or (obj.TypeId=="Part::Part2DObjectPython"):
- if obj.Name not in obj_list_prev:
- obj_list_after.append(obj.Name)
- #print obj_list_after #, obj_list_prev
- sk_to_conv=[]
+ if (
+ obj.TypeId in {"Part::Feature", "Sketcher::SketchObject", "Part::Part2DObjectPython"}
+ ) and obj.Name not in obj_list_prev:
+ obj_list_after.append(obj.Name)
+ # print obj_list_after #, obj_list_prev
+ sk_to_conv = []
for obj in doc.Objects:
if obj.Name in obj_list_after:
- if (obj.TypeId=="Part::Part2DObjectPython"):
+ if obj.TypeId == "Part::Part2DObjectPython":
FreeCAD.ActiveDocument.removeObject(obj.Name)
- FreeCAD.ActiveDocument.recompute()
+ FreeCAD.ActiveDocument.recompute()
else:
- sk_to_conv.append(obj.Name)
- keep_sketch_converted=True #False
+ sk_to_conv.append(obj.Name)
+ keep_sketch_converted = True # False
for s in sk_to_conv:
- #sayerr(s) ##
- ns=Discretize(s)
+ # sayerr(s) ##
+ ns = Discretize(s)
for g in geoBasic:
FreeCAD.ActiveDocument.getObject(ns).addGeometry(g)
- offset1=[-FreeCAD.ActiveDocument.getObject(sk_name).Placement.Base[0],-FreeCAD.ActiveDocument.getObject(sk_name).Placement.Base[1]]
- elist, to_dis=check_geom(ns,offset1)
+ offset1 = [
+ -FreeCAD.ActiveDocument.getObject(sk_name).Placement.Base[0],
+ -FreeCAD.ActiveDocument.getObject(sk_name).Placement.Base[1],
+ ]
+ elist, to_dis = check_geom(ns, offset1)
for e in elist:
- #print e[(len(e)-1):][0]
- e[(len(e)-1)]=sk_label
- #print e[(len(e)-1):][0]
- #stop
- new_edge_list=new_edge_list+elist
+ # print e[(len(e)-1):][0]
+ e[(len(e) - 1)] = sk_label
+ # print e[(len(e)-1):][0]
+ # stop
+ new_edge_list = new_edge_list + elist
if not keep_sketch_converted:
FreeCAD.ActiveDocument.removeObject(ns)
else:
- FreeCAD.ActiveDocument.getObject(ns).Label=sel[0].Label+'_simplified'
+ FreeCAD.ActiveDocument.getObject(ns).Label = sel[0].Label + "_simplified"
FreeCAD.ActiveDocument.recompute()
############# end discretizing
else:
- sayw('nothing to simplify')
+ sayw("nothing to simplify")
# to do: evaluate sanitize check
####stop
+
###
def simplify_sketch():
- ''' simplifying & sanitizing sketches '''
+ """simplifying & sanitizing sketches"""
global maxRadius, edge_tolerance, precision
-
+
doc = FreeCAD.ActiveDocument
sel = FreeCADGui.Selection.getSelection()
- if len(sel)==1:
- if 'Sketcher' in sel[0].TypeId:
+ if len(sel) == 1:
+ if "Sketcher" in sel[0].TypeId:
sanitizeSketch(sel[0].Name)
# new_edge_list, not_supported, to_discretize, construction_geom = getBoardOutline()
to_discretize = []
new_edge_list = []
- if hasattr(sel[0],'GeometryFacadeList'):
+ if hasattr(sel[0], "GeometryFacadeList"):
Gm = sel[0].GeometryFacadeList
for g in Gm:
- if 'BSplineCurve object' in str(g.Geometry):
+ if (
+ "BSplineCurve object" in str(g.Geometry)
+ or "Ellipse" in str(g.Geometry)
+ or "Parabola" in str(g.Geometry)
+ or "Hyperbola" in str(g.Geometry)
+ ):
to_discretize.append(g.Geometry)
- elif 'Ellipse' in str(g.Geometry) or 'Parabola' in str(g.Geometry) or 'Hyperbola' in str(g.Geometry):
- to_discretize.append(g.Geometry)
- else:
- if not isConstruction(g): #g.Construction: # adding only non construction geo
- new_edge_list.append(g.Geometry)
+ elif not isConstruction(g): # g.Construction: # adding only non construction geo
+ new_edge_list.append(g.Geometry)
else:
Gm = sel[0].Geometry
for g in Gm:
- if 'BSplineCurve object' in str(g):
+ if (
+ "BSplineCurve object" in str(g)
+ or "Ellipse" in str(g)
+ or "Parabola" in str(g)
+ or "Hyperbola" in str(g)
+ ):
to_discretize.append(g)
- elif 'Ellipse' in str(g) or 'Parabola' in str(g) or 'Hyperbola' in str(g):
- to_discretize.append(g)
- else:
- if not isConstruction(g): #g.Construction: # adding only non construction geo
- new_edge_list.append(g)
- #for g in sel[0].Geometry:
+ elif not isConstruction(g): # g.Construction: # adding only non construction geo
+ new_edge_list.append(g)
+ # for g in sel[0].Geometry:
## support for arcs, lines and bsplines in F_Silks
sel = FreeCADGui.Selection.getSelection()
- sk_name=None
- sk_name=sel[0].Name
- sk_label=sel[0].Label
-
- if len(to_discretize)>0 and sk_name is not None:
- FreeCADGui.ActiveDocument.getObject(sk_name).Visibility=False # hidden Sketch
- #sel = FreeCADGui.Selection.getSelection()
- #for s in sel:
+ sk_name = None
+ sk_name = sel[0].Name
+ sk_label = sel[0].Label
+
+ if len(to_discretize) > 0 and sk_name is not None:
+ FreeCADGui.ActiveDocument.getObject(sk_name).Visibility = False # hidden Sketch
+ # sel = FreeCADGui.Selection.getSelection()
+ # for s in sel:
# if 'F_Silks' in s.Label:
# sk_name=s.Name
- #if len (sel)==1:
- #sk_name=sel[0].Name
+ # if len (sel)==1:
+ # sk_name=sel[0].Name
for g in to_discretize:
- if 'Ellipse' in str(g) or 'BSpline' in str(g) or 'Hyperbol' in str(g) or 'Parabol' in str(g):
- bs = g.toBSpline() # (tolerance, maxSegments, maxDegree)
+ if "Ellipse" in str(g) or "BSpline" in str(g) or "Hyperbol" in str(g) or "Parabol" in str(g):
+ bs = g.toBSpline() # (tolerance, maxSegments, maxDegree)
try:
gds = bs.toBiArcs(precision)
- for gd in gds:
- new_edge_list.append(gd)
+ new_edge_list.extend(gds)
except:
- sayw('error in simplifying')
- pass
+ sayw("error in simplifying")
if len(new_edge_list) > 0:
- doc.addObject('Sketcher::SketchObject','sSketch')
+ doc.addObject("Sketcher::SketchObject", "sSketch")
ssk = doc.ActiveObject
- ssk_name = doc.ActiveObject.Name
ssk.Geometry = new_edge_list
# for i,g in enumerate (new_edge_list):
# if 'BSplineCurve object' in str(g):
# ssk.exposeInternalGeometry(i)
doc.recompute()
- ssk.Label = sk_label + u'_simplified'
-
+ ssk.Label = sk_label + "_simplified"
+
# t_name=cpy_sketch(sk_name)
# ###t_sk=FreeCAD.ActiveDocument.copyObject(FreeCAD.ActiveDocument.getObject(sk_name))
# elist, to_dis=check_geom(t_name)
@@ -17402,12 +18725,12 @@ def simplify_sketch():
# if obj.Name in obj_list_after:
# if (obj.TypeId=="Part::Part2DObjectPython"):
# FreeCAD.ActiveDocument.removeObject(obj.Name)
- # FreeCAD.ActiveDocument.recompute()
+ # FreeCAD.ActiveDocument.recompute()
# else:
# sk_to_conv.append(obj.Name)
# keep_sketch_converted=True #False
# for s in sk_to_conv:
- # #sayerr(s) ##
+ # #sayerr(s) ##
# ns=Discretize(s)
# for g in geoBasic:
# FreeCAD.ActiveDocument.getObject(ns).addGeometry(g)
@@ -17426,28 +18749,29 @@ def simplify_sketch():
# FreeCAD.ActiveDocument.recompute()
############# end discretizing
else:
- sayw('nothing to simplify')
+ sayw("nothing to simplify")
# to do: evaluate sanitize check
####stop
+
###
+
def normalize_bsplines():
- ''' simplifying & sanitizing sketches '''
+ """simplifying & sanitizing sketches"""
global edge_tolerance, maxRadius, maxSegments, precision
-
+
doc = FreeCAD.ActiveDocument
docG = FreeCADGui.ActiveDocument
sel = FreeCADGui.Selection.getSelection()
- if len(sel)==1:
- if 'Sketcher' in sel[0].TypeId:
+ if len(sel) == 1:
+ if "Sketcher" in sel[0].TypeId:
skGeo = sel[0].Geometry
found_to_simplify = False
kGeo = []
- #print(skGeo)
- maxDegree = 3 #kicad max degree of splines
+ # print(skGeo)
for g in skGeo:
- #if 'BSplineCurve object' in str(g):
+ # if 'BSplineCurve object' in str(g):
# bs = g
# # Set degree
# #maxDegree = 3 #kicad max degree of splines
@@ -17458,52 +18782,52 @@ def normalize_bsplines():
# bs = bs.approximateBSpline(edge_tolerance,maxSegment,maxDegree) # (tolerance, maxSegments, maxDegree)
# # Generate to a list of bezier curves
# import kicadStepUptools; import importlib; importlib.reload(kicadStepUptools)
- if 'Ellipse' in str(g) or 'Parabola' in str(g) or 'Hyperbola' in str(g):
- # bs = g.approximateBSpline(edge_tolerance,maxSegments,maxDegree) # (tolerance, maxSegments, maxDegree)
- bs = g.toBSpline() # (tolerance, maxSegments, maxDegree)
+ if "Ellipse" in str(g) or "Parabola" in str(g) or "Hyperbola" in str(g):
+ # bs = g.approximateBSpline(edge_tolerance,maxSegments,maxDegree) # (tolerance, maxSegments, maxDegree)
+ bs = g.toBSpline() # (tolerance, maxSegments, maxDegree)
bs = bs.toBiArcs(precision)
- for b in bs:
- kGeo.append(b)
+ kGeo.extend(bs)
found_to_simplify = True
- #print(bs)
- #stop
- else: #std geo like line, arcs, circles
+ # print(bs)
+ # stop
+ else: # std geo like line, arcs, circles
bs = g
kGeo.append(bs)
if found_to_simplify:
- doc.addObject('Sketcher::SketchObject','kBspSketch')
+ doc.addObject("Sketcher::SketchObject", "kBspSketch")
kbsp = doc.ActiveObject
- kbsp_name = doc.ActiveObject.Name
kbsp.Geometry = kGeo
- for i,g in enumerate (kGeo):
- if 'BSplineCurve object' in str(g):
+ for i, g in enumerate(kGeo):
+ if "BSplineCurve object" in str(g):
kbsp.exposeInternalGeometry(i)
doc.recompute()
docG.getObject(sel[0].Name).Visibility = False
- # bezier_list = bs.toBezier()
- # # Check the result
- # for bc in bezier_list:
- # print("%s (degree : %d / nb poles : %d)"%(bc, bc.Degree, bc.NbPoles))
- # print(bc, bc.Degree, bc.NbPoles)
- # Part.show(bc.toShape())
- # Draft.makeSketch(FreeCAD.ActiveDocument.ActiveObject,autoconstraints=True)
- # if not keep_sketch_converted:
- # FreeCAD.ActiveDocument.removeObject(ns)
- # else:
- # FreeCAD.ActiveDocument.getObject(ns).Label=sel[0].Label+'_simplified'
- # FreeCAD.ActiveDocument.recompute()
- ############# end discretizing
+ # bezier_list = bs.toBezier()
+ # # Check the result
+ # for bc in bezier_list:
+ # print("%s (degree : %d / nb poles : %d)"%(bc, bc.Degree, bc.NbPoles))
+ # print(bc, bc.Degree, bc.NbPoles)
+ # Part.show(bc.toShape())
+ # Draft.makeSketch(FreeCAD.ActiveDocument.ActiveObject,autoconstraints=True)
+ # if not keep_sketch_converted:
+ # FreeCAD.ActiveDocument.removeObject(ns)
+ # else:
+ # FreeCAD.ActiveDocument.getObject(ns).Label=sel[0].Label+'_simplified'
+ # FreeCAD.ActiveDocument.recompute()
+ ############# end discretizing
else:
- sayw('nothing to simplify')
+ sayw("nothing to simplify")
else:
- sayw('nothing to simplify')
+ sayw("nothing to simplify")
# to do: evaluate sanitize check
####stop
+
###
+
###
-def export_footprint(fname=None,flabel=None):
+def export_footprint(fname=None, flabel=None):
global last_fp_path, test_flag, start_time
global configParser, configFilePath, start_time
global ignore_utf8, ignore_utf8_incfg, disable_PoM_Observer
@@ -17511,551 +18835,595 @@ def export_footprint(fname=None,flabel=None):
global pcb_path, use_AppPart, force_oldGroups, use_Links, use_LinkGroups
global original_filename
global off_x, off_y, maxRadius, pad_nbr, dqd
-
- sayw('exporting new footprint')
- doc=FreeCAD.ActiveDocument
- #print fname
+
+ sayw("exporting new footprint")
+ doc = FreeCAD.ActiveDocument
+ # print fname
if fname is None:
- sayerr('missing fp file name')
+ sayerr("missing fp file name")
stop
# fpath=original_filename
else:
- fpath=fname
-
- sayerr('saving to '+fpath)
- #stop
-
+ fpath = fname
+
+ sayerr("saving to " + fpath)
+ # stop
+
if len(fpath) > 0:
- #new_edge_list=getBoardOutline()
- #say (new_edge_list)
+ # new_edge_list=getBoardOutline()
+ # say (new_edge_list)
cfg_read_all()
- path, fname = os.path.split(fpath)
- name=os.path.splitext(fname)[0]
- ext=os.path.splitext(fname)[1]
+ _path, fname = os.path.split(fpath)
+ os.path.splitext(fname)[0]
+ os.path.splitext(fname)[1]
fpth = os.path.dirname(os.path.abspath(fpath))
- #filePath = os.path.split(os.path.realpath(__file__))[0]
- #say ('my file path '+fpath)
+ # filePath = os.path.split(os.path.realpath(__file__))[0]
+ # say ('my file path '+fpath)
# stop
if fpth == "":
fpth = "."
last_fp_path = fpth
last_fp_path = re.sub("\\\\", "/", last_fp_path)
ini_vars[11] = last_fp_path
- #cfg_update_all()
+ # cfg_update_all()
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
pg.SetString("last_fp_path", make_string(last_fp_path))
- #sayerr(name+':'+ext)
+ # sayerr(name+':'+ext)
# old_dqd = dqd
# dqd=0.001
- new_edge_list, not_supported, to_discretize, construction_geom = getBoardOutline()
- #dqd=old_dqd
-
- #print (new_edge_list, to_discretize)
- #stop
-
+ new_edge_list, not_supported, to_discretize, _construction_geom = getBoardOutline()
+ # dqd=old_dqd
+
+ # print (new_edge_list, to_discretize)
+ # stop
+
## support for arcs, lines and bsplines in F_Silks
sel = FreeCADGui.Selection.getSelection()
- sk_name=None
+ sk_name = None
NetTie_present = False
- fp_name='fc_footprint'
- if flabel == '' or flabel is None:
- fp_name = FreeCAD.ActiveDocument.Name
- else:
- fp_name = flabel
- #print(fp_name, 'fp_name1')
-
+ fp_name = "fc_footprint"
+ fp_name = FreeCAD.ActiveDocument.Name if flabel == "" or flabel is None else flabel
+ # print(fp_name, 'fp_name1')
+
for s in sel:
- if 'F_Silks' in s.Label:
- sk_name=s.Name
- sk_label=s.Label
- if 'NetTie' in s.Label:
+ if "F_Silks" in s.Label:
+ sk_name = s.Name
+ sk_label = s.Label
+ if "NetTie" in s.Label:
NetTie_present = True
- if len(to_discretize)>0 and sk_name is not None:
- #sel = FreeCADGui.Selection.getSelection()
- #for s in sel:
+ if len(to_discretize) > 0 and sk_name is not None:
+ # sel = FreeCADGui.Selection.getSelection()
+ # for s in sel:
# if 'F_Silks' in s.Label:
# sk_name=s.Name
- #if len (sel)==1:
- #sk_name=sel[0].Name
- t_name=cpy_sketch(sk_name)
+ # if len (sel)==1:
+ # sk_name=sel[0].Name
+ t_name = cpy_sketch(sk_name)
###t_sk=FreeCAD.ActiveDocument.copyObject(FreeCAD.ActiveDocument.getObject(sk_name))
- elist, to_dis=check_geom(t_name)
- #Draft.clone(FreeCAD.ActiveDocument.getObject(sk_name),copy=True)
- #clone_name=App.ActiveDocument.ActiveObject.Name
+ elist, to_dis = check_geom(t_name)
+ # Draft.clone(FreeCAD.ActiveDocument.getObject(sk_name),copy=True)
+ # clone_name=App.ActiveDocument.ActiveObject.Name
remove_basic_geom(t_name, to_dis)
##remove_basic_geom(t_sk.Name, to_discretize)
##elist, to_dis=check_geom(t_sk.Name)
- #print elist
- #stop
- obj_list_prev=[]
+ # print elist
+ # stop
+ obj_list_prev = []
for obj in doc.Objects:
- #print obj.TypeId
- if (obj.TypeId=="Part::Feature") or (obj.TypeId=="Sketcher::SketchObject"):
+ # print obj.TypeId
+ if obj.TypeId in {"Part::Feature", "Sketcher::SketchObject"}:
obj_list_prev.append(obj.Name)
- #Draft.draftify(FreeCAD.ActiveDocument.getObject(t_name),delete=True)
- #Draft.draftify(FreeCAD.ActiveDocument.getObject(t_name),delete=False)
- b=FreeCAD.ActiveDocument.getObject(t_name)
- shp1=b.Shape.copy()
+ # Draft.draftify(FreeCAD.ActiveDocument.getObject(t_name),delete=True)
+ # Draft.draftify(FreeCAD.ActiveDocument.getObject(t_name),delete=False)
+ b = FreeCAD.ActiveDocument.getObject(t_name)
+ shp1 = b.Shape.copy()
Part.show(shp1)
FreeCAD.ActiveDocument.removeObject(t_name)
FreeCAD.ActiveDocument.recompute()
- #stop
- obj_list_after=[]
+ # stop
+ obj_list_after = []
for obj in doc.Objects:
- if (obj.TypeId=="Part::Feature") or (obj.TypeId=="Sketcher::SketchObject")\
- or (obj.TypeId=="Part::Part2DObjectPython"):
- if obj.Name not in obj_list_prev:
- obj_list_after.append(obj.Name)
- #print obj_list_after #, obj_list_prev
- sk_to_conv=[]
+ if (
+ obj.TypeId in {"Part::Feature", "Sketcher::SketchObject", "Part::Part2DObjectPython"}
+ ) and obj.Name not in obj_list_prev:
+ obj_list_after.append(obj.Name)
+ # print obj_list_after #, obj_list_prev
+ sk_to_conv = []
for obj in doc.Objects:
if obj.Name in obj_list_after:
- if (obj.TypeId=="Part::Part2DObjectPython"):
+ if obj.TypeId == "Part::Part2DObjectPython":
FreeCAD.ActiveDocument.removeObject(obj.Name)
- FreeCAD.ActiveDocument.recompute()
- elif (obj.TypeId=="Sketcher::SketchObject"):
- sk_to_conv.append(obj.Name)
- keep_sketch_converted=False #False
+ FreeCAD.ActiveDocument.recompute()
+ elif obj.TypeId == "Sketcher::SketchObject":
+ sk_to_conv.append(obj.Name)
+ keep_sketch_converted = False # False
for s in sk_to_conv:
- #sayerr(s) ##
- ns=Discretize(s)
- offset1=[-FreeCAD.ActiveDocument.getObject(sk_name).Placement.Base[0],-FreeCAD.ActiveDocument.getObject(sk_name).Placement.Base[1]]
- elist, to_dis=check_geom(ns,offset1)
+ # sayerr(s) ##
+ ns = Discretize(s)
+ offset1 = [
+ -FreeCAD.ActiveDocument.getObject(sk_name).Placement.Base[0],
+ -FreeCAD.ActiveDocument.getObject(sk_name).Placement.Base[1],
+ ]
+ elist, to_dis = check_geom(ns, offset1)
for e in elist:
- #print e[(len(e)-1):][0]
- e[(len(e)-1)]=sk_label
- #print e[(len(e)-1):][0]
- #stop
- new_edge_list=new_edge_list+elist
+ # print e[(len(e)-1):][0]
+ e[(len(e) - 1)] = sk_label
+ # print e[(len(e)-1):][0]
+ # stop
+ new_edge_list = new_edge_list + elist
if not keep_sketch_converted:
FreeCAD.ActiveDocument.removeObject(ns)
FreeCAD.ActiveDocument.recompute()
############# end discretizing
-
- new_border=u''
- #print (new_edge_list)
- #stop
+
+ new_border = ""
+ # print (new_edge_list)
+ # stop
## maxRadius # 4000 = 4m max length for KiCad
- #edge_nbr=0
- sanitized_edge_list=[]
+ # edge_nbr=0
+ sanitized_edge_list = []
for border in new_edge_list:
- #print border # [0]
- if 'arc' in border[0]:
- #print border[0]
+ # print border # [0]
+ if "arc" in border[0]:
+ # print border[0]
if abs(float(border[3])) > maxRadius:
- #print 'too big radius= ',border[3]
- #print 'border len= ', len(border)
- #points=border [10].x
- p1x = float("{0:.6f}".format(border [10].x));p1y=float("{0:.6f}".format(border [10].y))
- #print p1x, ' ',p1y
- p2x = float("{0:.6f}".format(border [11].x));p2y=float("{0:.6f}".format(border [11].y))
- #print '1st point ', border [10],' 2nd point ', border [11]
- sanitized_edge_list.append(['line',p1x,p1y,p2x,p2y,border[13]])
+ # print 'too big radius= ',border[3]
+ # print 'border len= ', len(border)
+ # points=border [10].x
+ p1x = float(f"{border[10].x:.6f}")
+ p1y = float(f"{border[10].y:.6f}")
+ # print p1x, ' ',p1y
+ p2x = float(f"{border[11].x:.6f}")
+ p2y = float(f"{border[11].y:.6f}")
+ # print '1st point ', border [10],' 2nd point ', border [11]
+ sanitized_edge_list.append(["line", p1x, p1y, p2x, p2y, border[13]])
else:
sanitized_edge_list.append(border)
else:
sanitized_edge_list.append(border)
- #edge_nbr=edge_nbr+1
+ # edge_nbr=edge_nbr+1
# print '------------------'
- #print (sanitized_edge_list)
+ # print (sanitized_edge_list)
####stop
- #for border in new_edge_list:
- reference=u"FC_"; value=u"Val_";
- xr= 0.0; yr=1.0;xv= 0.0; yv=-1.0
- #sel = FreeCADGui.Selection.getSelection()
- fsize='1.0 1.0'; fthick='0.15'
- ref_fsize='1.0 1.0'; ref_fthick='0.15'
- val_fsize='1.0 1.0'; val_fthick='0.15'
+ # for border in new_edge_list:
+ reference = "FC_"
+ value = "Val_"
+ xr = 0.0
+ yr = 1.0
+ xv = 0.0
+ yv = -1.0
+ # sel = FreeCADGui.Selection.getSelection()
+ ref_fsize = "1.0 1.0"
+ ref_fthick = "0.15"
+ val_fsize = "1.0 1.0"
+ val_fthick = "0.15"
for o in FreeCAD.ActiveDocument.Objects:
- #if sel[0].TypeId =='App::DocumentObjectGroup':
- #if o.TypeId =='App::DocumentObjectGroup':
+ # if sel[0].TypeId =='App::DocumentObjectGroup':
+ # if o.TypeId =='App::DocumentObjectGroup':
# fp_name=o.Label
# print(fp_name, 'fp_name2')
-
- #else:
+
+ # else:
# fp_name = FreeCAD.ActiveDocument.Name
- if o.TypeId =='App::Annotation':
- if 'Ref' in o.Label:
- reference=o.LabelText[0]
- xr=o.Position.x;yr=-o.Position.y
- fsize_list = o.Label.split('_')
- l = len (fsize_list)
+ if o.TypeId == "App::Annotation":
+ if "Ref" in o.Label:
+ reference = o.LabelText[0]
+ xr = o.Position.x
+ yr = -o.Position.y
+ fsize_list = o.Label.split("_")
+ l = len(fsize_list)
if l > 1:
- fs = (fsize_list[l-1].rstrip('mm'));
- ref_fsize=(fs+' '+fs); ref_fthick="{0:.3f}".format((float(fs)*0.15))
+ fs = fsize_list[l - 1].rstrip("mm")
+ ref_fsize = fs + " " + fs
+ ref_fthick = f"{float(fs) * 0.15:.3f}"
else:
- ref_fsize='1.0 1.0'; ref_fthick='0.15'
- elif 'Val' in o.Label:
- value=o.LabelText[0]
- xv=o.Position.x;yv=-o.Position.y
- fsize_list = o.Label.split('_')
- l = len (fsize_list)
+ ref_fsize = "1.0 1.0"
+ ref_fthick = "0.15"
+ elif "Val" in o.Label:
+ value = o.LabelText[0]
+ xv = o.Position.x
+ yv = -o.Position.y
+ fsize_list = o.Label.split("_")
+ l = len(fsize_list)
if l > 1:
- fs = (fsize_list[l-1].rstrip('mm'));
- val_fsize=(fs+' '+fs); val_fthick="{0:.3f}".format((float(fs)*0.15))
+ fs = fsize_list[l - 1].rstrip("mm")
+ val_fsize = fs + " " + fs
+ val_fthick = f"{float(fs) * 0.15:.3f}"
else:
- val_fsize='1.0 1.0'; val_fthick='0.15'
- offset=[0,0]
- drills=[];psmd=[];pth=[];npth=[]
- pply=[];ntply=[];prrect=[];pgeom=[];pgeomG=[]
- pads_TH_SMD=[];pads_NPTH=[]
- fzply=[];edge_thick=0.
- #edge_thick=0.15 #; lyr='F.SilkS'
+ val_fsize = "1.0 1.0"
+ val_fthick = "0.15"
+ offset = [0, 0]
+ drills = []
+ pth = []
+ npth = []
+ pply = []
+ ntply = []
+ prrect = []
+ pgeom = []
+ pgeomG = []
+ pads_TH_SMD = []
+ pads_NPTH = []
+ fzply = []
+ edge_thick = 0.0
+ # edge_thick=0.15 #; lyr='F.SilkS'
# lyr=border[len(border-1):]
## header=u"(module "+fp_name+" (layer F.Cu) (tedit 5A74E519)"+os.linesep
- #header=header+fp_type
- #header=header+" (descr \""+fp_name+" StepUp generated footprint\")"+os.linesep
+ # header=header+fp_type
+ # header=header+" (descr \""+fp_name+" StepUp generated footprint\")"+os.linesep
# print(fp_name, 'fp_name3')
- header=" (descr \""+fp_name.replace('-fp','')+" StepUp generated footprint\")"+os.linesep
+ header = ' (descr "' + fp_name.replace("-fp", "") + ' StepUp generated footprint")' + os.linesep
if NetTie_present:
- header=header+" (tags \"net tie\")"+os.linesep
+ header = header + ' (tags "net tie")' + os.linesep
# header=header+" (attr virtual)"
- header=header+" (fp_text reference \""+reference+u"\" (at "+str(xr)+" "+str(yr)+") (layer F.SilkS)"+os.linesep
- header=header+" (effects (font (size "+ref_fsize+") (thickness "+ref_fthick+")))"+os.linesep
- header=header+" )"+os.linesep
- header=header+" (fp_text value \""+value+u"\" (at "+str(xv)+" "+str(yv)+") (layer F.SilkS)"+os.linesep
- header=header+" (effects (font (size "+val_fsize+") (thickness "+val_fthick+")))"+os.linesep
- #header=header+" (effects (font (size 1.0 1.0) (thickness 0.15)))"+os.linesep
- header=header+" )"+os.linesep
- header=header+" (fp_text user %R (at "+str(xr)+" "+str(yr)+") (layer F.Fab)"+os.linesep
- header=header+" (effects (font (size "+ref_fsize+") (thickness "+ref_fthick+")))"+os.linesep
- #header=header+" (effects (font (size 1 1) (thickness 0.15)))"+os.linesep
- header=header+" )"+os.linesep
- header=header+" (fp_text user \"EDIT PAD NUMBERS\" (at "+str(xv)+" "+str(yv-1)+") (layer Cmts.User)"+os.linesep
- header=header+" (effects (font (size 1 1) (thickness 0.2) italic))"+os.linesep
- header=header+" )"
+ header = (
+ header
+ + ' (fp_text reference "'
+ + reference
+ + '" (at '
+ + str(xr)
+ + " "
+ + str(yr)
+ + ") (layer F.SilkS)"
+ + os.linesep
+ )
+ header = header + " (effects (font (size " + ref_fsize + ") (thickness " + ref_fthick + ")))" + os.linesep
+ header = header + " )" + os.linesep
+ header = (
+ header
+ + ' (fp_text value "'
+ + value
+ + '" (at '
+ + str(xv)
+ + " "
+ + str(yv)
+ + ") (layer F.SilkS)"
+ + os.linesep
+ )
+ header = header + " (effects (font (size " + val_fsize + ") (thickness " + val_fthick + ")))" + os.linesep
+ # header=header+" (effects (font (size 1.0 1.0) (thickness 0.15)))"+os.linesep
+ header = header + " )" + os.linesep
+ header = header + " (fp_text user %R (at " + str(xr) + " " + str(yr) + ") (layer F.Fab)" + os.linesep
+ header = header + " (effects (font (size " + ref_fsize + ") (thickness " + ref_fthick + ")))" + os.linesep
+ # header=header+" (effects (font (size 1 1) (thickness 0.15)))"+os.linesep
+ header = header + " )" + os.linesep
+ header = (
+ header
+ + ' (fp_text user "EDIT PAD NUMBERS" (at '
+ + str(xv)
+ + " "
+ + str(yv - 1)
+ + ") (layer Cmts.User)"
+ + os.linesep
+ )
+ header = header + " (effects (font (size 1 1) (thickness 0.2) italic))" + os.linesep
+ header = header + " )"
## import kicadStepUptools; reload(kicadStepUptools)
for border in sanitized_edge_list:
- #print (border)
- edge_thick=0.05
- lyr=border[(len(border)-1):][0]
- lyr_splt = lyr.split('_')
- tk_d=0.1
- #print(lyr)
- if 'CrtYd' in lyr:
- if len(lyr_splt)>=3:
- tk=lyr.split('_')[len(lyr_splt)-1]
- if tk!='':
- edge_thick=float(tk)
- else:
- edge_thick=tk_d
- lyr=u'F.CrtYd'
+ # print (border)
+ edge_thick = 0.05
+ lyr = border[(len(border) - 1) :][0]
+ lyr_splt = lyr.split("_")
+ tk_d = 0.1
+ # print(lyr)
+ if "CrtYd" in lyr:
+ if len(lyr_splt) >= 3:
+ tk = lyr.split("_")[len(lyr_splt) - 1]
+ edge_thick = float(tk) if tk != "" else tk_d
+ lyr = "F.CrtYd"
else:
- lyr='skip'
- elif 'Silks' in lyr:
- if len(lyr_splt)>=3:
- tk=lyr.split('_')[len(lyr_splt)-1]
- if tk!='':
- edge_thick=float(tk)
- else:
- edge_thick=tk_d
- lyr=u'F.SilkS'
+ lyr = "skip"
+ elif "Silks" in lyr:
+ if len(lyr_splt) >= 3:
+ tk = lyr.split("_")[len(lyr_splt) - 1]
+ edge_thick = float(tk) if tk != "" else tk_d
+ lyr = "F.SilkS"
else:
- lyr='skip'
- elif 'Fab' in lyr:
- if len(lyr_splt)>=3:
- tk=lyr.split('_')[len(lyr_splt)-1]
- if tk!='':
- edge_thick=float(tk)
- else:
- edge_thick=tk_d
- lyr=u'F.Fab'
+ lyr = "skip"
+ elif "Fab" in lyr:
+ if len(lyr_splt) >= 3:
+ tk = lyr.split("_")[len(lyr_splt) - 1]
+ edge_thick = float(tk) if tk != "" else tk_d
+ lyr = "F.Fab"
else:
- lyr='skip'
- elif 'Dwgs' in lyr:
- if len(lyr_splt)>=2:
- tk=lyr.split('_')[len(lyr_splt)-1]
- if tk!='':
- edge_thick=float(tk)
- else:
- edge_thick=tk_d
- lyr=u'Dwgs.User'
+ lyr = "skip"
+ elif "Dwgs" in lyr:
+ if len(lyr_splt) >= 2:
+ tk = lyr.split("_")[len(lyr_splt) - 1]
+ edge_thick = float(tk) if tk != "" else tk_d
+ lyr = "Dwgs.User"
else:
- lyr='skip'
- elif 'Cmts' in lyr:
- if len(lyr_splt)>=2:
- tk=lyr.split('_')[len(lyr_splt)-1]
- if tk!='':
- edge_thick=float(tk)
- else:
- edge_thick=tk_d
- lyr=u'Cmts.User'
+ lyr = "skip"
+ elif "Cmts" in lyr:
+ if len(lyr_splt) >= 2:
+ tk = lyr.split("_")[len(lyr_splt) - 1]
+ edge_thick = float(tk) if tk != "" else tk_d
+ lyr = "Cmts.User"
else:
- lyr='skip'
- elif 'Cuts' in lyr:
- if len(lyr_splt)>=3:
- tk=lyr.split('_')[len(lyr_splt)-1]
- if tk!='':
- edge_thick=float(tk)
- else:
- edge_thick=tk_d
- lyr=u'Edge.Cuts'
+ lyr = "skip"
+ elif "Cuts" in lyr:
+ if len(lyr_splt) >= 3:
+ tk = lyr.split("_")[len(lyr_splt) - 1]
+ edge_thick = float(tk) if tk != "" else tk_d
+ lyr = "Edge.Cuts"
else:
- lyr='skip'
- #elif 'Pads_SMD' in lyr:
+ lyr = "skip"
+ # elif 'Pads_SMD' in lyr:
# edge_thick=0.
# lyr=u'Pads_SMD'
# psmd.append(border)
- #elif 'Pads_TH' in lyr and not 'SMD' in lyr:
+ # elif 'Pads_TH' in lyr and not 'SMD' in lyr:
# edge_thick=0.
# lyr=u'Pads_TH'
# pth.append(border)
- #elif 'Drills' in lyr:
+ # elif 'Drills' in lyr:
# edge_thick=0.
# lyr=u'Drills'
# drills.append(border)
- elif 'NPTH' in lyr:
- edge_thick=0.
- lyr=u'NPTH'
+ elif "NPTH" in lyr:
+ edge_thick = 0.0
+ lyr = "NPTH"
pads_NPTH.append(border)
- elif 'Pads_Poly' in lyr:
- edge_thick=0.
- if 0: #'B_Cu' in lyr:
- lyr=u'Pad_Poly_B_Cu'
+ elif "Pads_Poly" in lyr:
+ edge_thick = 0.0
+ if 0: #'B_Cu' in lyr:
+ lyr = "Pad_Poly_B_Cu"
else:
- lyr=u'Pad_Poly'
+ lyr = "Pad_Poly"
pply.append(border)
- elif 'NetTie_Poly' in lyr:
- edge_thick=0.
- if 0: #'B_Cu' in lyr:
- lyr=u'NetTie_Poly_B_Cu'
+ elif "NetTie_Poly" in lyr:
+ edge_thick = 0.0
+ if 0: #'B_Cu' in lyr:
+ lyr = "NetTie_Poly_B_Cu"
else:
- lyr=u'NetTie_Poly'
+ lyr = "NetTie_Poly"
ntply.append(border)
- elif 'FZ_F_Mask' in lyr:
- edge_thick=0.
- lyr=u'FZ_Mask_Poly'
+ elif "FZ_F_Mask" in lyr:
+ edge_thick = 0.0
+ lyr = "FZ_Mask_Poly"
# fzply.append(border)
- elif 'Pads_Round_Rect' in lyr:
- edge_thick=0.
- if 0: #'B_Cu' in lyr:
- lyr=u'Pads_Round_Rect_B_Cu'
+ elif "Pads_Round_Rect" in lyr:
+ edge_thick = 0.0
+ if 0: #'B_Cu' in lyr:
+ lyr = "Pads_Round_Rect_B_Cu"
else:
- lyr=u'Pads_Round_Rect'
+ lyr = "Pads_Round_Rect"
prrect.append(border)
- elif 'Pads_TH' in lyr and 'SMD' in lyr:
- edge_thick=0.
- if 0: #'B_Cu' in lyr:
- lyr=u'PadsAll_B_Cu'
+ elif "Pads_TH" in lyr and "SMD" in lyr:
+ edge_thick = 0.0
+ if 0: #'B_Cu' in lyr:
+ lyr = "PadsAll_B_Cu"
else:
- lyr=u'PadsAll'
+ lyr = "PadsAll"
pads_TH_SMD.append(border)
- elif 'Pads_Geom' in lyr:
- #edge_thick=float(lyr.split('_')[2])
- if len(lyr_splt)>=3:
- tk=lyr.split('_')[len(lyr_splt)-1]
- if tk!='':
- edge_thick=float(tk)
- else:
- edge_thick=tk_d
- #print (lyr)
+ elif "Pads_Geom" in lyr:
+ # edge_thick=float(lyr.split('_')[2])
+ if len(lyr_splt) >= 3:
+ tk = lyr.split("_")[len(lyr_splt) - 1]
+ edge_thick = float(tk) if tk != "" else tk_d
+ # print (lyr)
sk = FreeCAD.ActiveDocument.getObjectsByLabel(lyr)[0]
- if hasattr(sk,'GeometryFacadeList'):
+ if hasattr(sk, "GeometryFacadeList"):
Gm = sk.GeometryFacadeList
for g in Gm:
- if isConstruction(g): # g.Construction:
- if 'Circle' in type(g.Geometry).__name__ and not 'ArcOfCircle' in type(g.Geometry).__name__:
- sk_ge=g.Geometry.toShape() #needed to fix some issue on sketch geometry building
- pgeomG.append([
- 'circle',
- sk_ge.Edges[0].Curve.Radius,
- sk_ge.Edges[0].Curve.Center.x,
- sk_ge.Edges[0].Curve.Center.y,
- sk.Label
- ])
+ if isConstruction(g): # g.Construction:
+ if "Circle" in type(g.Geometry).__name__ and "ArcOfCircle" not in type(g.Geometry).__name__:
+ sk_ge = g.Geometry.toShape() # needed to fix some issue on sketch geometry building
+ pgeomG.append(
+ [
+ "circle",
+ sk_ge.Edges[0].Curve.Radius,
+ sk_ge.Edges[0].Curve.Center.x,
+ sk_ge.Edges[0].Curve.Center.y,
+ sk.Label,
+ ],
+ )
else:
Gm = sk.Geometry
for g in Gm:
- if isConstruction(g): #g.Construction:
- if 'Circle' in type(g).__name__ and not 'ArcOfCircle' in type(g).__name__:
- sk_ge=g.toShape() #needed to fix some issue on sketch geometry building
- pgeomG.append([
- 'circle',
- sk_ge.Edges[0].Curve.Radius,
- sk_ge.Edges[0].Curve.Center.x,
- sk_ge.Edges[0].Curve.Center.y,
- sk.Label
- ])
- #lyr=u'Pads_Geom'
+ if isConstruction(g): # g.Construction:
+ if "Circle" in type(g).__name__ and "ArcOfCircle" not in type(g).__name__:
+ sk_ge = g.toShape() # needed to fix some issue on sketch geometry building
+ pgeomG.append(
+ [
+ "circle",
+ sk_ge.Edges[0].Curve.Radius,
+ sk_ge.Edges[0].Curve.Center.x,
+ sk_ge.Edges[0].Curve.Center.y,
+ sk.Label,
+ ],
+ )
+ # lyr=u'Pads_Geom'
pgeom.append(border)
- #print (pgeom);print(pgeomG)
- #sayw(prrect); sayw(pply)
- #sayw(pth)
-
- #if (lyr != 'Pads_SMD' and lyr != 'Pads_TH' and lyr != 'Drills' and lyr != 'NPTH'\
- if ('Pads_SMD' not in lyr and 'Pads_TH' not in lyr and 'Drills' not in lyr and 'NPTH' not in lyr \
- and 'Pad_Poly' not in lyr and 'NetTie_Poly' not in lyr and 'Pads_Round_Rect' not in lyr and 'PadsAll' not in lyr)\
- and 'Pads_Geom' not in lyr and 'skip' not in lyr and 'FZ_Mask_Poly' not in lyr:
- #print border, ' BORDER' #
- #if len (border)>0:
- new_border=new_border+os.linesep+createFp(border,offset, lyr, edge_thick)
- #sayw(createEdge(border))
- #stop
-
- #pth_ordered=collect_pads(psmd) #pads_all) ## pads normalized with sequence of segments
+ # print (pgeom);print(pgeomG)
+ # sayw(prrect); sayw(pply)
+ # sayw(pth)
+
+ # if (lyr != 'Pads_SMD' and lyr != 'Pads_TH' and lyr != 'Drills' and lyr != 'NPTH'\
+ if (
+ (
+ "Pads_SMD" not in lyr
+ and "Pads_TH" not in lyr
+ and "Drills" not in lyr
+ and "NPTH" not in lyr
+ and "Pad_Poly" not in lyr
+ and "NetTie_Poly" not in lyr
+ and "Pads_Round_Rect" not in lyr
+ and "PadsAll" not in lyr
+ )
+ and "Pads_Geom" not in lyr
+ and "skip" not in lyr
+ and "FZ_Mask_Poly" not in lyr
+ ):
+ # print border, ' BORDER' #
+ # if len (border)>0:
+ new_border = new_border + os.linesep + createFp(border, offset, lyr, edge_thick)
+ # sayw(createEdge(border))
+ # stop
+
+ # pth_ordered=collect_pads(psmd) #pads_all) ## pads normalized with sequence of segments
## normalizing TH and SMD pads
- if len(pads_TH_SMD) >0:
- pth_ordered=collect_pads(pads_TH_SMD) #pads_all) ## pads normalized with sequence of segments
+ if len(pads_TH_SMD) > 0:
+ pth_ordered = collect_pads(pads_TH_SMD) # pads_all) ## pads normalized with sequence of segments
## search for drills (pads inside pads)
- drl_found=collect_drl(pth_ordered)
- #sayerr (pth_ordered)
- #sayw(drl_found)
- ## impiling pads
- pads_TH_SMD=[]
+ drl_found = collect_drl(pth_ordered)
+ # sayerr (pth_ordered)
+ # sayw(drl_found)
+ ## impiling pads
+ pads_TH_SMD = []
for p in pth_ordered:
for e in p:
- pads_TH_SMD.append (e)
+ pads_TH_SMD.append(e)
# print len(pads_TH_SMD)
- pth=[]
- pth=pads_TH_SMD
- ## impiling pads
- drills=[]
+ pth = []
+ pth = pads_TH_SMD
+ ## impiling pads
+ drills = []
for p in drl_found:
for e in p:
- drills.append (e)
+ drills.append(e)
# print len(drills)
- #print psmd
- #stop
-
+ # print psmd
+ # stop
+
## normalizing NPTH pads
- if len(pads_NPTH) >0:
- pth_ordered=collect_pads(pads_NPTH) #pads_all) ## pads normalized with sequence of segments
+ if len(pads_NPTH) > 0:
+ pth_ordered = collect_pads(pads_NPTH) # pads_all) ## pads normalized with sequence of segments
## search for drills (pads inside pads)
- drl_found=collect_drl(pth_ordered)
- #sayerr (pth_ordered)
- #sayw(drl_found)
- #stop
- ## impiling pads
- pads_NPTH=[]
+ drl_found = collect_drl(pth_ordered)
+ # sayerr (pth_ordered)
+ # sayw(drl_found)
+ # stop
+ ## impiling pads
+ pads_NPTH = []
for p in pth_ordered:
for e in p:
- pads_NPTH.append (e)
+ pads_NPTH.append(e)
# print len(pads_NPTH)
- npth=[]
- npth=pads_NPTH
- ## impiling pads
- #drills=[]
+ npth = []
+ npth = pads_NPTH
+ ## impiling pads
+ # drills=[]
for p in drl_found:
for e in p:
- drills.append (e)
+ drills.append(e)
# print len(drills)
- #print psmd
- #stop
-
+ # print psmd
+ # stop
+
## normalizing Round Rect pads
- if len(prrect) >0:
- pth_ordered=collect_pads(prrect) #pads_all) ## pads normalized with sequence of segments
+ if len(prrect) > 0:
+ pth_ordered = collect_pads(prrect) # pads_all) ## pads normalized with sequence of segments
## search for drills (pads inside pads)
- drl_found=collect_drl(pth_ordered)
- #sayerr (pth_ordered)
- #sayw(drl_found)
- #stop
- ## impiling pads
- prrect=[]
+ drl_found = collect_drl(pth_ordered)
+ # sayerr (pth_ordered)
+ # sayw(drl_found)
+ # stop
+ ## impiling pads
+ prrect = []
for p in pth_ordered:
for e in p:
- prrect.append (e)
- #print len(prrect)
- if len (prrect)>0:
- sayw('normalized Round Rect')
- #print prrect
- #npth=[]
- #npth=pads_NPTH
- ## impiling pads
- #drills=[]
+ prrect.append(e)
+ # print len(prrect)
+ if len(prrect) > 0:
+ sayw("normalized Round Rect")
+ # print prrect
+ # npth=[]
+ # npth=pads_NPTH
+ ## impiling pads
+ # drills=[]
for p in drl_found:
for e in p:
- drills.append (e)
- #print len(drills)
- #print psmd
- #stop
-
+ drills.append(e)
+ # print len(drills)
+ # print psmd
+ # stop
+
## normalizing Poly pads
- if len(pply) >0:
- #print(pply)
- pth_ordered=collect_pads(pply) #pads_all) ## pads normalized with sequence of segments
- #sayerr(pth_ordered);sayerr(len(pth_ordered))
- ## impiling pads
- #drl_found=collect_drl(pth_ordered)
-
- pply=[]
+ if len(pply) > 0:
+ # print(pply)
+ pth_ordered = collect_pads(pply) # pads_all) ## pads normalized with sequence of segments
+ # sayerr(pth_ordered);sayerr(len(pth_ordered))
+ ## impiling pads
+ # drl_found=collect_drl(pth_ordered)
+
+ pply = []
for p in pth_ordered:
for e in p:
- pply.append (e)
- #print len(prrect)
- if len (pply)>0:
- sayw('normalized Poly')
- # ## impiling pads
+ pply.append(e)
+ # print len(prrect)
+ if len(pply) > 0:
+ sayw("normalized Poly")
+ # ## impiling pads
# for p in drl_found:
# for e in p:
# drills.append (e)
- #print prrect
- #npth=[]
- #npth=pads_NPTH
- #print len(drills)
- #print psmd
- #stop
+ # print prrect
+ # npth=[]
+ # npth=pads_NPTH
+ # print len(drills)
+ # print psmd
+ # stop
## normalizing NetTie Poly
- if len(ntply) >0:
- #sayerr(ntply)
- pth_ordered=collect_pads(ntply) #pads_all) ## pads normalized with sequence of segments
- #sayerr(pth_ordered)
- ## impiling pads
- #drl_found=collect_drl(pth_ordered)
-
- ntply=[]
+ if len(ntply) > 0:
+ # sayerr(ntply)
+ pth_ordered = collect_pads(ntply) # pads_all) ## pads normalized with sequence of segments
+ # sayerr(pth_ordered)
+ ## impiling pads
+ # drl_found=collect_drl(pth_ordered)
+
+ ntply = []
for p in pth_ordered:
for e in p:
- ntply.append (e)
- #print len(prrect)
- if len (ntply)>0:
- sayw('normalized NetTie Poly')
+ ntply.append(e)
+ # print len(prrect)
+ if len(ntply) > 0:
+ sayw("normalized NetTie Poly")
## normalizing Geom pads
- pGm=[]
- if len(pgeomG) >0:
- pth_ordered=collect_pads(pgeomG) #pads_all) ## pads normalized with sequence of segments
- #sayerr(pth_ordered)
- ## impiling pads
- drl_found=collect_drl(pth_ordered)
+ pGm = []
+ if len(pgeomG) > 0:
+ pth_ordered = collect_pads(pgeomG) # pads_all) ## pads normalized with sequence of segments
+ # sayerr(pth_ordered)
+ ## impiling pads
+ drl_found = collect_drl(pth_ordered)
print(drl_found)
- pGm=[]
+ pGm = []
for p in pth_ordered:
for e in p:
- pGm.append (e)
- #print len(prrect)
- if len (pGm)>0:
- sayw('normalized Geom')
- #print(pGm)
- # ## impiling pads
+ pGm.append(e)
+ # print len(prrect)
+ if len(pGm) > 0:
+ sayw("normalized Geom")
+ # print(pGm)
+ # ## impiling pads
# for p in drl_found:
# for e in p:
# drills.append (e)
- #print prrect
- #npth=[]
- #npth=pads_NPTH
- #print len(drills)
- #print psmd
- #stop
-
+ # print prrect
+ # npth=[]
+ # npth=pads_NPTH
+ # print len(drills)
+ # print psmd
+ # stop
+
## writing content
- newcontent=u''+header
- #new_edge=new_border+os.linesep+')'+os.linesep
- #newcontent=newcontent+new_edge+u' '
- if len (new_border)>0:
- newcontent=newcontent+new_border #+os.linesep
- #print newcontent
-
+ newcontent = "" + header
+ # new_edge=new_border+os.linesep+')'+os.linesep
+ # newcontent=newcontent+new_edge+u' '
+ if len(new_border) > 0:
+ newcontent = newcontent + new_border # +os.linesep
+ # print newcontent
+
#### ----------SMD-------------------------------
- #npad=u''
- #mpad=[]
- #nline=1
- #pad_nbr=1
- #found_arc=False
- #for pad in psmd:
+ # npad=u''
+ # mpad=[]
+ # nline=1
+ # pad_nbr=1
+ # found_arc=False
+ # for pad in psmd:
# if pad[0]=='circle':
# npad=npad+os.linesep+createFpPad(pad,offset,u'SMD')
# elif pad[0]=='line' and not found_arc:
@@ -18074,23 +19442,23 @@ def export_footprint(fname=None,flabel=None):
# mpad=[]
# found_arc=False
# nline=nline+1
- #if len (npad)>0:
+ # if len (npad)>0:
# newcontent=newcontent+npad+os.linesep
# sayw('created SMD pads')
### ----------Drills-------------------------------
- #print psmd
- mdrills=[]
- pad_nbr=1
- nline=1
- drill_pos=[]
- found_arc=False
- #sayerr(drills)
+ # print psmd
+ mdrills = []
+ pad_nbr = 1
+ nline = 1
+ drill_pos = []
+ found_arc = False
+ # sayerr(drills)
for drill in drills:
- #sayerr(drill)
- if drill[0]=='circle':
- #ret=createFpPad(drill,offset,u'Drills')
- #sayw(ret)
- drill_pos.append(createFpPad(drill,offset,u'Drills'))
+ # sayerr(drill)
+ if drill[0] == "circle":
+ # ret=createFpPad(drill,offset,u'Drills')
+ # sayw(ret)
+ drill_pos.append(createFpPad(drill, offset, "Drills"))
# elif drill[0]=='line' and not found_arc:
# mdrills.append(drill)
# if nline>=4:
@@ -18099,127 +19467,136 @@ def export_footprint(fname=None,flabel=None):
# nline=0
# mdrills=[]
# nline=nline+1
- elif drill[0]=='arc' or (drill[0]=='line' and found_arc):
- found_arc=True
+ elif drill[0] == "arc" or (drill[0] == "line" and found_arc):
+ found_arc = True
mdrills.append(drill)
- #print('arc or line + '+str(nline))
- if nline>=4:
- #ndrill=ndrill+os.linesep+createFpPad(mdrills,offset,u'Drills')
- drill_pos.append(createFpPad(mdrills,offset,u'Drills'))
- nline=0
- mdrills=[]
- found_arc=False
- nline=nline+1
- #sayw(drill_pos)
+ # print('arc or line + '+str(nline))
+ if nline >= 4:
+ # ndrill=ndrill+os.linesep+createFpPad(mdrills,offset,u'Drills')
+ drill_pos.append(createFpPad(mdrills, offset, "Drills"))
+ nline = 0
+ mdrills = []
+ found_arc = False
+ nline = nline + 1
+ # sayw(drill_pos)
## drill_pos (cntX,cntY,sizeX,sizeY)
- fp_type=' (attr smd)'+os.linesep
- if len (drill_pos)>0:
- #newcontent=newcontent+os.linesep+')'+os.linesep+u' '
- sayw ('collected drills centers and positions')
- fp_type=''
- #re.sub(r'^[^\n]*\n', '', s)
- newcontent=u"(module "+fp_name.replace('-fp','')+" (layer F.Cu) (tedit 61218795)"+os.linesep+newcontent
+ fp_type = " (attr smd)" + os.linesep
+ if len(drill_pos) > 0:
+ # newcontent=newcontent+os.linesep+')'+os.linesep+u' '
+ sayw("collected drills centers and positions")
+ fp_type = ""
+ # re.sub(r'^[^\n]*\n', '', s)
+ newcontent = (
+ "(module " + fp_name.replace("-fp", "") + " (layer F.Cu) (tedit 61218795)" + os.linesep + newcontent
+ )
else:
- newcontent=u"(module "+fp_name.replace('-fp','')+" (layer F.Cu) (tedit 61218795)"+os.linesep+fp_type+newcontent
-
- #header=header+fp_type
- ### ----------TH-------------------------------
- npad=u''
- mpad=[]
- nline=1
- pad_nbr=1
- found_arc=False
+ newcontent = (
+ "(module "
+ + fp_name.replace("-fp", "")
+ + " (layer F.Cu) (tedit 61218795)"
+ + os.linesep
+ + fp_type
+ + newcontent
+ )
+
+ # header=header+fp_type
+ ### ----------TH-------------------------------
+ npad = ""
+ mpad = []
+ nline = 1
+ pad_nbr = 1
+ found_arc = False
for pad in pth:
- if pad[0]=='circle':
- npad=npad+os.linesep+createFpPad(pad,offset,u'TH', drill_pos)
- elif pad[0]=='line' and not found_arc:
+ if pad[0] == "circle":
+ npad = npad + os.linesep + createFpPad(pad, offset, "TH", drill_pos)
+ elif pad[0] == "line" and not found_arc:
mpad.append(pad)
- if nline>=4:
- npad=npad+os.linesep+createFpPad(mpad,offset,u'TH', drill_pos)
- nline=0
- mpad=[]
- nline=nline+1
- elif pad[0]=='arc' or (pad[0]=='line' and found_arc):
- found_arc=True
+ if nline >= 4:
+ npad = npad + os.linesep + createFpPad(mpad, offset, "TH", drill_pos)
+ nline = 0
+ mpad = []
+ nline = nline + 1
+ elif pad[0] == "arc" or (pad[0] == "line" and found_arc):
+ found_arc = True
mpad.append(pad)
- if nline>=4:
- npad=npad+os.linesep+createFpPad(mpad,offset,u'TH', drill_pos)
- nline=0
- mpad=[]
- found_arc=False
- nline=nline+1
-
- #print 'len pad '+str(len(npad))
-
- #print newcontent
- if len (npad)>0:
- newcontent=newcontent+npad+os.linesep
- say('created TH pads')
+ if nline >= 4:
+ npad = npad + os.linesep + createFpPad(mpad, offset, "TH", drill_pos)
+ nline = 0
+ mpad = []
+ found_arc = False
+ nline = nline + 1
+
+ # print 'len pad '+str(len(npad))
+
+ # print newcontent
+ if len(npad) > 0:
+ newcontent = newcontent + npad + os.linesep
+ say("created TH pads")
### ----------NPTH-------------------------------
- npad=u''
- mpad=[]
- nline=1
- pad_nbr=1
- found_arc=False
+ npad = ""
+ mpad = []
+ nline = 1
+ pad_nbr = 1
+ found_arc = False
for pad in npth:
- if pad[0]=='circle':
- npad=npad+os.linesep+createFpPad(pad,offset,u'NPTH', drill_pos)
- elif pad[0]=='line' and not found_arc:
+ if pad[0] == "circle":
+ npad = npad + os.linesep + createFpPad(pad, offset, "NPTH", drill_pos)
+ elif pad[0] == "line" and not found_arc:
mpad.append(pad)
- if nline>=4:
- npad=npad+os.linesep+createFpPad(mpad,offset,u'NPTH', drill_pos)
- nline=0
- mpad=[]
- nline=nline+1
- elif pad[0]=='arc' or (pad[0]=='line' and found_arc):
- found_arc=True
+ if nline >= 4:
+ npad = npad + os.linesep + createFpPad(mpad, offset, "NPTH", drill_pos)
+ nline = 0
+ mpad = []
+ nline = nline + 1
+ elif pad[0] == "arc" or (pad[0] == "line" and found_arc):
+ found_arc = True
mpad.append(pad)
- if nline>=4:
- npad=npad+os.linesep+createFpPad(mpad,offset,u'NPTH', drill_pos)
- nline=0
- mpad=[]
- found_arc=False
- nline=nline+1
-
- #print 'len pad '+str(len(npad))
- #print newcontent
- if len (npad)>0:
- newcontent=newcontent+npad+os.linesep
- say('created NPTH pads')
+ if nline >= 4:
+ npad = npad + os.linesep + createFpPad(mpad, offset, "NPTH", drill_pos)
+ nline = 0
+ mpad = []
+ found_arc = False
+ nline = nline + 1
+
+ # print 'len pad '+str(len(npad))
+ # print newcontent
+ if len(npad) > 0:
+ newcontent = newcontent + npad + os.linesep
+ say("created NPTH pads")
### ----------Round Rect-------------------------------
- npad=u''
- mpad=[]
- nline=1
- pad_nbr=1
- found_arc=False
- #found_line=False
+ npad = ""
+ mpad = []
+ nline = 1
+ pad_nbr = 1
+ found_arc = False
+ # found_line=False
for pad in prrect:
- #sayw('RRect type '+pad[0])
- #sayerr(pad)
- #if pad[0]=='circle':
+ # sayw('RRect type '+pad[0])
+ # sayerr(pad)
+ # if pad[0]=='circle':
# npad=npad+os.linesep+createFpPad(pad,offset,u'NPTH', drill_pos)
- #if pad[0]=='line' and not found_arc:
- if pad[0]=='arc' and not found_arc:
+ # if pad[0]=='line' and not found_arc:
+ if pad[0] == "arc" and not found_arc:
mpad.append(pad)
- found_arc=True
- nline=nline+1
- #elif pad[0]=='arc' or (pad[0]=='line' and found_arc):
- elif (nline<=8 and found_arc):
+ found_arc = True
+ nline = nline + 1
+ # elif pad[0]=='arc' or (pad[0]=='line' and found_arc):
+ elif nline <= 8 and found_arc:
mpad.append(pad)
- #print mpad
- #print nline
- if nline>=8:
- #print npad
- #print 'd pos ',drill_pos
- #print 'mpad';print mpad
- #print 'offset ',offset
- #stop
- npad=npad+os.linesep+createFpPad(mpad,offset,u'RoundRect', drill_pos)
- nline=0
- mpad=[]
- found_arc=False
- nline=nline+1
- #print npad
+ # print mpad
+ # print nline
+ if nline >= 8:
+ # print npad
+ # print 'd pos ',drill_pos
+ # print 'mpad';print mpad
+ # print 'offset ',offset
+ # stop
+ npad = npad + os.linesep + createFpPad(mpad, offset, "RoundRect", drill_pos)
+ nline = 0
+ mpad = []
+ found_arc = False
+ nline = nline + 1
+ # print npad
# ### ----------Round Rect-------------------------------
# npad=u''
# mpad=[]
@@ -18247,28 +19624,28 @@ def export_footprint(fname=None,flabel=None):
# mpad=[]
# found_arc=False
# nline=nline+1
- # #print npad
-
- #print 'len pad '+str(len(npad))
- #print newcontent
- if len (npad)>0:
- newcontent=newcontent+npad+os.linesep
- say('created Round Rect pads')
+ # #print npad
+
+ # print 'len pad '+str(len(npad))
+ # print newcontent
+ if len(npad) > 0:
+ newcontent = newcontent + npad + os.linesep
+ say("created Round Rect pads")
### ----------Poly reference Pad-------------------------------
- #print psmd
- polypad=[]
- polypad=pply
- pad_nbr=1
- nline=1
- polypad_pos=[]
- found_arc=False
- #sayerr(polypad)
+ # print psmd
+ polypad = []
+ polypad = pply
+ pad_nbr = 1
+ nline = 1
+ polypad_pos = []
+ found_arc = False
+ # sayerr(polypad)
for circ_pad in polypad:
- #sayerr(drill)
- if circ_pad[0]=='circle':
- #ret=createFpPad(drill,offset,u'Drills')
- #sayw(circ_pad)
- polypad_pos.append(createFpPad(circ_pad,offset,u'Drills'))
+ # sayerr(drill)
+ if circ_pad[0] == "circle":
+ # ret=createFpPad(drill,offset,u'Drills')
+ # sayw(circ_pad)
+ polypad_pos.append(createFpPad(circ_pad, offset, "Drills"))
# elif drill[0]=='line' and not found_arc:
# mdrills.append(drill)
# if nline>=4:
@@ -18277,74 +19654,74 @@ def export_footprint(fname=None,flabel=None):
# nline=0
# mdrills=[]
# nline=nline+1
-
- #sayw(drill_pos)
+
+ # sayw(drill_pos)
## drill_pos (cntX,cntY,sizeX,sizeY)
- if len (polypad_pos)>0:
- #newcontent=newcontent+os.linesep+')'+os.linesep+u' '
- sayw ('collected poly pads centers and positions')
- #print(polypad_pos, 'poly pad pos')
- #print(pply,'pl geo')
+ if len(polypad_pos) > 0:
+ # newcontent=newcontent+os.linesep+')'+os.linesep+u' '
+ sayw("collected poly pads centers and positions")
+ # print(polypad_pos, 'poly pad pos')
+ # print(pply,'pl geo')
### ----------Poly-------------------------------
- #polypad_pos=[] ### TBC polypad inside poly sketch
- #sayerr(pply)
- #sayerr(polypad_pos)
- npad=u''
- mpad=[]
- nline=1
- pad_nbr=1
- poly_closed=False
+ # polypad_pos=[] ### TBC polypad inside poly sketch
+ # sayerr(pply)
+ # sayerr(polypad_pos)
+ npad = ""
+ mpad = []
+ nline = 1
+ pad_nbr = 1
+ poly_closed = False
for pad in pply:
- #sayerr(pad)
- #print('pad',pad)
- #if pad[0]=='circle':
+ # sayerr(pad)
+ # print('pad',pad)
+ # if pad[0]=='circle':
# npad=npad+os.linesep+createFpPad(pad,offset,u'NPTH', drill_pos)
- if pad[0]=='line':
+ if pad[0] == "line":
mpad.append(pad)
- if len(mpad)>1:
- if abs(mpad[0][1]-pad[3]) 1:
+ if abs(mpad[0][1] - pad[3]) < edge_tolerance and abs(mpad[0][2] - pad[4]) < edge_tolerance:
+ # print(mpad[0][1],pad[3],mpad[0][2],pad[4])
+ sayerr("poly closed")
+ poly_closed = True
+ nline = 1
+ # pad_nbr=pad_nbr+1
else:
- nline=nline+1
+ nline = nline + 1
if poly_closed:
- #print npad
- #print ('mpad', mpad)
- #print ('polypad_pos', polypad_pos)
- poly_closed=False
- if 0: #'B_Cu' in lyr:
- npad=npad+os.linesep+createFpPad(mpad,offset,u'Poly_B_Cu', polypad_pos)
+ # print npad
+ # print ('mpad', mpad)
+ # print ('polypad_pos', polypad_pos)
+ poly_closed = False
+ if 0: #'B_Cu' in lyr:
+ npad = npad + os.linesep + createFpPad(mpad, offset, "Poly_B_Cu", polypad_pos)
else:
- npad=npad+os.linesep+createFpPad(mpad,offset,u'Poly', polypad_pos)
- nline=1
- mpad=[]
- #nline=nline+1
- #print npad
-
- #print 'len pad '+str(len(npad))
- #print newcontent
- if len (npad)>0:
- newcontent=newcontent+npad+os.linesep
- say('created Poly pads')
+ npad = npad + os.linesep + createFpPad(mpad, offset, "Poly", polypad_pos)
+ nline = 1
+ mpad = []
+ # nline=nline+1
+ # print npad
+
+ # print 'len pad '+str(len(npad))
+ # print newcontent
+ if len(npad) > 0:
+ newcontent = newcontent + npad + os.linesep
+ say("created Poly pads")
### ----------NetTie Poly reference pad -------------------------------
- #print psmd
- polypad=[]
- polypad=ntply
- pad_nbr=1
- nline=1
- polypad_pos=[]
- found_arc=False
- #sayerr(polypad)
+ # print psmd
+ polypad = []
+ polypad = ntply
+ pad_nbr = 1
+ nline = 1
+ polypad_pos = []
+ found_arc = False
+ # sayerr(polypad)
for circ_pad in polypad:
- #sayerr(drill)
- if circ_pad[0]=='circle':
- #ret=createFpPad(drill,offset,u'Drills')
- #sayw(circ_pad)
- polypad_pos.append(createFpPad(circ_pad,offset,u'Drills'))
+ # sayerr(drill)
+ if circ_pad[0] == "circle":
+ # ret=createFpPad(drill,offset,u'Drills')
+ # sayw(circ_pad)
+ polypad_pos.append(createFpPad(circ_pad, offset, "Drills"))
# elif drill[0]=='line' and not found_arc:
# mdrills.append(drill)
# if nline>=4:
@@ -18353,150 +19730,172 @@ def export_footprint(fname=None,flabel=None):
# nline=0
# mdrills=[]
# nline=nline+1
-
- #sayw(drill_pos)
+
+ # sayw(drill_pos)
## drill_pos (cntX,cntY,sizeX,sizeY)
- if len (polypad_pos)>0:
- #newcontent=newcontent+os.linesep+')'+os.linesep+u' '
- sayw ('collected net tie poly pads centers and positions')
- #print(polypad_pos, 'poly pad pos')
- #print(ntply,'nt geo')
+ if len(polypad_pos) > 0:
+ # newcontent=newcontent+os.linesep+')'+os.linesep+u' '
+ sayw("collected net tie poly pads centers and positions")
+ # print(polypad_pos, 'poly pad pos')
+ # print(ntply,'nt geo')
### ----------Poly-------------------------------
- #polypad_pos=[] ### TBC polypad inside poly sketch
- #sayerr(pply)
- #sayerr(polypad_pos)
- npad=u''
- mpad=[]
- nline=1
- pad_nbr=1
- poly_closed=False
+ # polypad_pos=[] ### TBC polypad inside poly sketch
+ # sayerr(pply)
+ # sayerr(polypad_pos)
+ npad = ""
+ mpad = []
+ nline = 1
+ pad_nbr = 1
+ poly_closed = False
for pad in ntply:
- #sayerr(pad)
- #if pad[0]=='circle':
+ # sayerr(pad)
+ # if pad[0]=='circle':
# npad=npad+os.linesep+createFpPad(pad,offset,u'NPTH', drill_pos)
- if pad[0]=='line':
+ if pad[0] == "line":
mpad.append(pad)
- if len(mpad)>1:
- if abs(mpad[0][1]-pad[3]) 1:
+ if abs(mpad[0][1] - pad[3]) < edge_tolerance and abs(mpad[0][2] - pad[4]) < edge_tolerance:
+ sayerr("poly closed")
+ poly_closed = True
+ nline = 1
+ # pad_nbr=pad_nbr+1
else:
- nline=nline+1
+ nline = nline + 1
if poly_closed:
- #print npad
- #print 'mpad';print mpad
- poly_closed=False
- if 0: #'B_Cu' in lyr:
- npad=npad+os.linesep+createFpPad(mpad,offset,u'NetTie_Poly_B_Cu', polypad_pos)
+ # print npad
+ # print 'mpad';print mpad
+ poly_closed = False
+ if 0: #'B_Cu' in lyr:
+ npad = npad + os.linesep + createFpPad(mpad, offset, "NetTie_Poly_B_Cu", polypad_pos)
else:
- npad=npad+os.linesep+createFpPad(mpad,offset,u'NetTie_Poly', polypad_pos)
- nline=1
- mpad=[]
- #nline=nline+1
- #print npad
-
- #print 'len pad '+str(len(npad))
- #print newcontent
- if len (npad)>0:
- newcontent=newcontent+npad+os.linesep
- say('created NetTie Poly pads')
+ npad = npad + os.linesep + createFpPad(mpad, offset, "NetTie_Poly", polypad_pos)
+ nline = 1
+ mpad = []
+ # nline=nline+1
+ # print npad
+
+ # print 'len pad '+str(len(npad))
+ # print newcontent
+ if len(npad) > 0:
+ newcontent = newcontent + npad + os.linesep
+ say("created NetTie Poly pads")
### ----------FZ Poly-------------------------------
- #polypad_pos=[] ### TBC polypad inside poly sketch
- #sayerr(pply)
- #sayerr(polypad_pos)
- #sel = FreeCADGui.Selection.getSelection()
- npad=u''
+ # polypad_pos=[] ### TBC polypad inside poly sketch
+ # sayerr(pply)
+ # sayerr(polypad_pos)
+ # sel = FreeCADGui.Selection.getSelection()
+ npad = ""
for s in sel:
- poly_closed=False
- polypad_pos=None
- print(o.Label,'parsing sketch')
- pts=""
- if 'FZ_F_Mask' in s.Label:
- #print('s.Label',s.Label)
- ns=Discretize(s.Name,'dont_delete',0.001) #NB use don't delete and pass discretization value
- face = OSCD2Dg_edgestofaces(FreeCAD.ActiveDocument.getObject(ns).Shape.Edges,3 , edge_tolerance)
+ poly_closed = False
+ polypad_pos = None
+ print(o.Label, "parsing sketch")
+ pts = ""
+ if "FZ_F_Mask" in s.Label:
+ # print('s.Label',s.Label)
+ ns = Discretize(s.Name, "dont_delete", 0.001) # NB use don't delete and pass discretization value
+ face = OSCD2Dg_edgestofaces(FreeCAD.ActiveDocument.getObject(ns).Shape.Edges, 3, edge_tolerance)
FreeCAD.ActiveDocument.removeObject(ns)
- #FreeCAD.ActiveDocument.recompute()
- face.check() # reports errors
- face.fix(0,0,0)
- ws=face.Wires
- #print(face.Wires,len(face.Wires),'face')
+ # FreeCAD.ActiveDocument.recompute()
+ face.check() # reports errors
+ face.fix(0, 0, 0)
+ ws = face.Wires
+ # print(face.Wires,len(face.Wires),'face')
if 0:
Part.show(face)
- f=FreeCAD.ActiveDocument.ActiveObject
- ws=f.Shape.Wires
- print(ws,len(ws),'face2')
- padLayer="F.Mask"
- j=0
+ f = FreeCAD.ActiveDocument.ActiveObject
+ ws = f.Shape.Wires
+ print(ws, len(ws), "face2")
+ padLayer = "F.Mask"
+ j = 0
for w in ws:
- j=j+1
+ j = j + 1
# cls=Part.getSortedClusters(w.Edges)
# print(cls)
- clusters = Part.sortEdges(w.Edges) #[0]
- #print(len(clusters))
+ clusters = Part.sortEdges(w.Edges) # [0]
+ # print(len(clusters))
for cluster in clusters:
- # cluster=clusters[0]
- # if 1:
- #print(len(cluster))
- pts+=" (fp_poly"+os.linesep+" (pts"+os.linesep
- for i,e in enumerate(cluster): #w.Edges):
- #print('i',i)
- if i < len(cluster)-1:
- pts=pts+" (xy "+"{0:.3f}".format(e.Vertexes[0].X)+" "+"{0:.3f}".format(-1*(e.Vertexes[0].Y))+") (xy "+"{0:.3f}".format(e.Vertexes[1].X)+" "+"{0:.3f}".format(-1*(e.Vertexes[1].Y))+")"+os.linesep
+ # cluster=clusters[0]
+ # if 1:
+ # print(len(cluster))
+ pts += " (fp_poly" + os.linesep + " (pts" + os.linesep
+ for i, e in enumerate(cluster): # w.Edges):
+ # print('i',i)
+ if i < len(cluster) - 1:
+ pts = (
+ pts
+ + " (xy "
+ + f"{e.Vertexes[0].X:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[0].Y):.3f}"
+ + ") (xy "
+ + f"{e.Vertexes[1].X:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[1].Y):.3f}"
+ + ")"
+ + os.linesep
+ )
else:
- pts=pts+" (xy "+"{0:.3f}".format(e.Vertexes[0].X)+" "+"{0:.3f}".format(-1*(e.Vertexes[0].Y))+")) (layer \""+padLayer+"\") (width 0))"+os.linesep
+ pts = (
+ pts
+ + " (xy "
+ + f"{e.Vertexes[0].X:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[0].Y):.3f}"
+ + ')) (layer "'
+ + padLayer
+ + '") (width 0))'
+ + os.linesep
+ )
# print(pts,'\npts',j)
- #print('j',j)
- if len (pts)>0:
- newcontent=newcontent+os.linesep+pts+os.linesep
- say('created FZ Poly pads')
- # npad=npad+os.linesep+pts
+ # print('j',j)
+ if len(pts) > 0:
+ newcontent = newcontent + os.linesep + pts + os.linesep
+ say("created FZ Poly pads")
+ # npad=npad+os.linesep+pts
# stop
- #stop
- if 0: # len(fzply)>0:
- #print(fzply,len(fzply))
- #stop
- npad=npad+os.linesep+createFpPad(fzply,offset,u'FZ_Mask_Poly', polypad_pos)
-
+ # stop
+ if 0: # len(fzply)>0:
+ # print(fzply,len(fzply))
+ # stop
+ npad = npad + os.linesep + createFpPad(fzply, offset, "FZ_Mask_Poly", polypad_pos)
+
if 0:
for pad in fzply:
# print(fzply)
- #stop
- #sayerr(pad)
- #if pad[0]=='circle':
+ # stop
+ # sayerr(pad)
+ # if pad[0]=='circle':
# npad=npad+os.linesep+createFpPad(pad,offset,u'NPTH', drill_pos)
- ## wr.append(Part.makeLine((pad[1], pad[2],0.0),(pad[3], pad[4],0.0)))
- ## for w in wr:
- ## sortedEdges = Part.__sortEdges__(w.Edges)
- ## wire = Part.Wire(sortedEdges)
- ##
- if pad[0]=='line':
+ ## wr.append(Part.makeLine((pad[1], pad[2],0.0),(pad[3], pad[4],0.0)))
+ ## for w in wr:
+ ## sortedEdges = Part.__sortEdges__(w.Edges)
+ ## wire = Part.Wire(sortedEdges)
+ ##
+ if pad[0] == "line":
mpad.append(pad)
- #print(pad)
- if len(mpad)>2:
- #print(mpad)
- if abs(mpad[0][1]-pad[3]) 2:
+ # print(mpad)
+ if abs(mpad[0][1] - pad[3]) < edge_tolerance and abs(mpad[0][2] - pad[4]) < edge_tolerance:
+ # if abs(mpad[0][3]-pad[1])0:
- newcontent=newcontent+npad+os.linesep
- say('created FZ Poly pads')
+
+ # print 'len pad '+str(len(npad))
+ # print newcontent
+ if 0: # len (npad)>0:
+ newcontent = newcontent + npad + os.linesep
+ say("created FZ Poly pads")
### ----------Geom reference Pad-------------------------------
- #print psmd
- pgeompad=[]
- pgeompad=pGm
- pad_nbr=1
- nline=1
- pgeompad_pos=[]
- found_arc=False
- #sayerr(polypad)
+ # print psmd
+ pgeompad = []
+ pgeompad = pGm
+ pad_nbr = 1
+ nline = 1
+ pgeompad_pos = []
+ found_arc = False
+ # sayerr(polypad)
for circ_pad in pgeompad:
- #sayerr(drill)
- if circ_pad[0]=='circle':
- #ret=createFpPad(drill,offset,u'Drills')
- #sayw(circ_pad)
- pgeompad_pos.append(createFpPad(circ_pad,offset,u'Drills'))
+ # sayerr(drill)
+ if circ_pad[0] == "circle":
+ # ret=createFpPad(drill,offset,u'Drills')
+ # sayw(circ_pad)
+ pgeompad_pos.append(createFpPad(circ_pad, offset, "Drills"))
# elif drill[0]=='line' and not found_arc:
# mdrills.append(drill)
# if nline>=4:
@@ -18545,414 +19943,428 @@ def export_footprint(fname=None,flabel=None):
# nline=0
# mdrills=[]
# nline=nline+1
-
- #sayw(drill_pos)
+
+ # sayw(drill_pos)
## drill_pos (cntX,cntY,sizeX,sizeY)
- if len (pgeompad_pos)>0:
- #newcontent=newcontent+os.linesep+')'+os.linesep+u' '
- sayw ('collected geometry pads centers and positions')
+ if len(pgeompad_pos) > 0:
+ # newcontent=newcontent+os.linesep+')'+os.linesep+u' '
+ sayw("collected geometry pads centers and positions")
sayw(pgeompad_pos)
### ----------Primitive Geometry-------------------------------
## only Circle supported ATM
- #polypad_pos=[] ### TBC polypad inside poly sketch
- #sayerr(pply)
- #sayerr(polypad_pos)
- npad=u''
- mpad=[]
- nline=1
- pad_nbr=1
- #say (pgeom)
- #stop
- i=0
+ # polypad_pos=[] ### TBC polypad inside poly sketch
+ # sayerr(pply)
+ # sayerr(polypad_pos)
+ npad = ""
+ mpad = []
+ nline = 1
+ pad_nbr = 1
+ # say (pgeom)
+ # stop
+ i = 0
for pad in pgeom:
- #sayerr(pad)
- #if pad[0]=='circle':
+ # sayerr(pad)
+ # if pad[0]=='circle':
# npad=npad+os.linesep+createFpPad(pad,offset,u'NPTH', drill_pos)
- if pad[0]=='line':
- sayw('line not suported')
- if pad[0]=='circle':
- #print npad
- #print 'mpad';print mpad
+ if pad[0] == "line":
+ sayw("line not suported")
+ if pad[0] == "circle":
+ # print npad
+ # print 'mpad';print mpad
mpad.append(pad)
- npad=npad+os.linesep+createFpPad(mpad,offset,u'Pads_Geom', [pgeompad_pos[i]])
- nline=1
- mpad=[]
- i+=1
- #nline=nline+1
- #print npad
-
- #print 'len pad '+str(len(npad))
- #print newcontent
- if len (npad)>0:
- newcontent=newcontent+npad+os.linesep
- say('created Geom pads')
-
+ npad = npad + os.linesep + createFpPad(mpad, offset, "Pads_Geom", [pgeompad_pos[i]])
+ nline = 1
+ mpad = []
+ i += 1
+ # nline=nline+1
+ # print npad
+
+ # print 'len pad '+str(len(npad))
+ # print newcontent
+ if len(npad) > 0:
+ newcontent = newcontent + npad + os.linesep
+ say("created Geom pads")
+
## adding 3D model preset
- newcontent+=os.linesep+u" (model \""+str(fpth)+os.sep+fp_name.rstrip('-fp')+u'.wrl\"'+os.linesep
- newcontent+=u" (at (xyz 0 0 0))"+os.linesep
- newcontent+=u" (scale (xyz 1 1 1))"+os.linesep
- newcontent+=u" (rotate (xyz 0 0 0))"+os.linesep
- newcontent+=u" )"+os.linesep
+ newcontent += os.linesep + ' (model "' + str(fpth) + os.sep + fp_name.rstrip("-fp") + '.wrl"' + os.linesep
+ newcontent += " (at (xyz 0 0 0))" + os.linesep
+ newcontent += " (scale (xyz 1 1 1))" + os.linesep
+ newcontent += " (rotate (xyz 0 0 0))" + os.linesep
+ newcontent += " )" + os.linesep
### ---------- wrtiting file --------------------
- newcontent=newcontent+')'+os.linesep+u' '
- #dqd=old_dqd
-
- with codecs.open(fpath,'w', encoding='utf-8') as ofile:
+ newcontent = newcontent + ")" + os.linesep + " "
+ # dqd=old_dqd
+
+ with codecs.open(fpath, "w", encoding="utf-8") as ofile:
ofile.write(newcontent)
- ofile.close()
+ ofile.close()
say_time()
- msg="""new Footprint pushed to kicad footprint!
"""
- msg+="file saved to
"+fpath+"
"
- msgr="new Footprint pushed to kicad footprint!\n"
- msgr+="file saved to "+fpath+"\n"
- lns=len (not_supported)
- #print lns
+ msg = """new Footprint pushed to kicad footprint!
"""
+ msg += "file saved to
" + fpath + "
"
+ msgr = "new Footprint pushed to kicad footprint!\n"
+ msgr += "file saved to " + fpath + "\n"
+ lns = len(not_supported)
+ # print lns
if lns > 2:
- if lns < 103: # writing only some geometry not supported
- msg+="
found downgraded Geometry:
"+not_supported[:-2]+"!"
- msgr+="\nfound downgraded Geometry: "+not_supported[:-2]+"!"
+ if lns < 103: # writing only some geometry not supported
+ msg += "
found downgraded Geometry:
" + not_supported[:-2] + "!"
+ msgr += "\nfound downgraded Geometry: " + not_supported[:-2] + "!"
else:
- nss=not_supported[:-2]
- nss=nss[:101]+'...
...'
- msg+="
found downgraded Geometry:
"+nss+""
- msgr+="\nfound downgraded Geometry: "+not_supported[:-2]+"!"
-
+ nss = not_supported[:-2]
+ nss = nss[:101] + "...
..."
+ msg += "
found downgraded Geometry:
" + nss + ""
+ msgr += "\nfound downgraded Geometry: " + not_supported[:-2] + "!"
+
say(msgr)
say_info(msg)
- #if not edge_pcb_exists:
+ # if not edge_pcb_exists:
# msg="close your FC Sketch
and reload the kicad_pcb file"
# say_warning(msg)
-
-
+
+
###
def collect_drl(pads):
- pad_shps=[] #pad,center,shape
+ pad_shps = [] # pad,center,shape
if pads is not None:
for p in pads:
- #sayw(p)
- #print p[0][0] ;print p[0][2]
- if p[0][0]=='circle':
- p_center=(p[0][2],p[0][3],0)
- p_radius=p[0][1]
- #print p_center
- wr=Part.Wire(Part.makeCircle(p_radius, Base.Vector(p_center)))
- ps=Part.Wire(wr)
+ # sayw(p)
+ # print p[0][0] ;print p[0][2]
+ if p[0][0] == "circle":
+ p_center = (p[0][2], p[0][3], 0)
+ p_radius = p[0][1]
+ # print p_center
+ wr = Part.Wire(Part.makeCircle(p_radius, Base.Vector(p_center)))
+ ps = Part.Wire(wr)
face = Part.Face(ps)
Part.show(face)
- shpName=FreeCAD.ActiveDocument.ActiveObject.Name
- #say( FreeCAD.ActiveDocument.ActiveObject.Label)
- shape= FreeCAD.ActiveDocument.ActiveObject.Shape
- pad_shps.append([p,p_center,shpName])
- elif p[0][0] =='arc' and 'Pads_Round_Rect' in p[0][len(p[0])-1]:
- sayw('round rect')
- #print p
- r1=p[0][1]; cx1=p[0][2]; cy1=p[0][3]
- #print 'r1 ', r1, ' c1 ', cx1,',',cy1
- r2=p[2][1]; cx2=p[2][2]; cy2=p[2][3]
- #print 'r2 ', r2, ' c2 ', cx2,',',cy2
- #stop
- if abs(cx1-cx2)>edge_tolerance: # horizontal
- sayerr('horizontal')
- #print p
- px=(p[0][10].x+p[2][10].x)/2;
- py=(p[0][10].y+p[2][10].y)/2;
- sx=2*r1+abs(p[1][1]-p[3][1]);
- sy=2*r1+abs(p[1][2]-p[1][4])
- #print r1,' ',sx-2*r1
- else: #vertical
- sayerr('vertical')
- #print p[0][10].x
- #print p[2][10].x
- px=(p[0][10].x+p[2][10].x)/2;
- py=(p[0][10].y+p[2][10].y)/2;
- sx=2*r1+abs(p[3][1]-p[3][3]);
- sy=2*r1+abs(p[1][2]-p[1][4])
- p_center=(px,py,0)
- #Draft.makePoint(px,py, 0)
- wr=[]
- #print p
- #arc -> approximate shape with rectangle
- wr.append(Part.makeLine((px-sx/2, py-sy/2,0.0),(px-sx/2, py+sy/2,0.0)))
- wr.append(Part.makeLine((px-sx/2, py+sy/2,0.0),(px+sx/2, py+sy/2,0.0)))
- wr.append(Part.makeLine((px+sx/2, py+sy/2,0.0),(px+sx/2, py-sy/2,0.0)))
- wr.append(Part.makeLine((px+sx/2, py-sy/2,0.0),(px-sx/2, py-sy/2,0.0)))
-
- ps=Part.Wire(wr)
+ shpName = FreeCAD.ActiveDocument.ActiveObject.Name
+ # say( FreeCAD.ActiveDocument.ActiveObject.Label)
+ pad_shps.append([p, p_center, shpName])
+ elif p[0][0] == "arc" and "Pads_Round_Rect" in p[0][len(p[0]) - 1]:
+ sayw("round rect")
+ # print p
+ r1 = p[0][1]
+ cx1 = p[0][2]
+ p[0][3]
+ # print 'r1 ', r1, ' c1 ', cx1,',',cy1
+ p[2][1]
+ cx2 = p[2][2]
+ p[2][3]
+ # print 'r2 ', r2, ' c2 ', cx2,',',cy2
+ # stop
+ if abs(cx1 - cx2) > edge_tolerance: # horizontal
+ sayerr("horizontal")
+ # print p
+ px = (p[0][10].x + p[2][10].x) / 2
+ py = (p[0][10].y + p[2][10].y) / 2
+ sx = 2 * r1 + abs(p[1][1] - p[3][1])
+ sy = 2 * r1 + abs(p[1][2] - p[1][4])
+ # print r1,' ',sx-2*r1
+ else: # vertical
+ sayerr("vertical")
+ # print p[0][10].x
+ # print p[2][10].x
+ px = (p[0][10].x + p[2][10].x) / 2
+ py = (p[0][10].y + p[2][10].y) / 2
+ sx = 2 * r1 + abs(p[3][1] - p[3][3])
+ sy = 2 * r1 + abs(p[1][2] - p[1][4])
+ p_center = (px, py, 0)
+ # Draft.makePoint(px,py, 0)
+ wr = []
+ # print p
+ # arc -> approximate shape with rectangle
+ wr.append(Part.makeLine((px - sx / 2, py - sy / 2, 0.0), (px - sx / 2, py + sy / 2, 0.0)))
+ wr.append(Part.makeLine((px - sx / 2, py + sy / 2, 0.0), (px + sx / 2, py + sy / 2, 0.0)))
+ wr.append(Part.makeLine((px + sx / 2, py + sy / 2, 0.0), (px + sx / 2, py - sy / 2, 0.0)))
+ wr.append(Part.makeLine((px + sx / 2, py - sy / 2, 0.0), (px - sx / 2, py - sy / 2, 0.0)))
+
+ ps = Part.Wire(wr)
face = Part.Face(ps)
Part.show(face)
- #stop
- shpName=FreeCAD.ActiveDocument.ActiveObject.Name
- #say( FreeCAD.ActiveDocument.ActiveObject.Label)
- shape= FreeCAD.ActiveDocument.ActiveObject.Shape
- pad_shps.append([p,p_center,shpName])
- elif p[0][0]=='line':
- #print p
- px=(p[0][1]+p[0][3])/2;py=(p[1][2]+p[1][4])/2;
- if abs(p[0][1]-p[0][3]) >0:
- sx=abs(p[0][1]-p[0][3])
- px=(p[0][1]+p[0][3])/2
+ # stop
+ shpName = FreeCAD.ActiveDocument.ActiveObject.Name
+ # say( FreeCAD.ActiveDocument.ActiveObject.Label)
+ pad_shps.append([p, p_center, shpName])
+ elif p[0][0] == "line":
+ # print p
+ px = (p[0][1] + p[0][3]) / 2
+ py = (p[1][2] + p[1][4]) / 2
+ if abs(p[0][1] - p[0][3]) > 0:
+ sx = abs(p[0][1] - p[0][3])
+ px = (p[0][1] + p[0][3]) / 2
else:
- sx=abs(p[1][1]-p[1][3])
- px=(p[1][1]+p[1][3])/2
- if abs(p[1][2]-p[1][4]) >0:
- sy=abs(p[1][2]-p[1][4])
- py=(p[1][2]+p[1][4])/2;
+ sx = abs(p[1][1] - p[1][3])
+ px = (p[1][1] + p[1][3]) / 2
+ if abs(p[1][2] - p[1][4]) > 0:
+ sy = abs(p[1][2] - p[1][4])
+ py = (p[1][2] + p[1][4]) / 2
else:
- sy=abs(p[0][2]-p[0][4])
- py=(p[0][2]+p[0][4])/2;
+ sy = abs(p[0][2] - p[0][4])
+ py = (p[0][2] + p[0][4]) / 2
# Draft.makePoint(px,py, 0)
- #print p[0];print p[1]
- #stop
- p_center=(px,py,0)
- wr=[]
+ # print p[0];print p[1]
+ # stop
+ p_center = (px, py, 0)
+ wr = []
for lines in p:
- wr.append(Part.makeLine((lines[1], lines[2],0.0),(lines[3], lines[4],0.0)))
- ps=Part.Wire(wr)
+ wr.append(Part.makeLine((lines[1], lines[2], 0.0), (lines[3], lines[4], 0.0)))
+ ps = Part.Wire(wr)
face = Part.Face(ps)
Part.show(face)
- #stop
- shpName=FreeCAD.ActiveDocument.ActiveObject.Name
- #say( FreeCAD.ActiveDocument.ActiveObject.Label)
- shape= FreeCAD.ActiveDocument.ActiveObject.Shape
- pad_shps.append([p,p_center,shpName])
- elif p[0][0]=='arc':
- #print pad
- r1=p[0][1]; cx1=p[0][2]; cy1=p[0][3]
- #print 'r1 ', r1, ' c1 ', cx1,',',cy1
- r2=p[2][1]; cx2=p[2][2]; cy2=p[2][3]
- #print 'r2 ', r2, ' c2 ', cx2,',',cy2
- #stop
- if abs(cx1-cx2)>edge_tolerance: # horizontal
- sayerr('horizontal')
- px=(p[0][10].x+p[2][11].x)/2;py=(p[0][11].y+p[2][11].y)/2;
- sx=2*r1+abs((p[0][10].x-p[2][11].x)); sy=2*r1
- else: #vertical
- sayerr('vertical')
- px=(p[0][10].x+p[0][11].x)/2;py=(p[0][10].y+p[2][10].y)/2;
- sx=2*r1; sy=2*r1+abs((p[0][10].y-p[2][10].y))
- p_center=(px,py,0)
+ # stop
+ shpName = FreeCAD.ActiveDocument.ActiveObject.Name
+ # say( FreeCAD.ActiveDocument.ActiveObject.Label)
+ pad_shps.append([p, p_center, shpName])
+ elif p[0][0] == "arc":
+ # print pad
+ r1 = p[0][1]
+ cx1 = p[0][2]
+ p[0][3]
+ # print 'r1 ', r1, ' c1 ', cx1,',',cy1
+ p[2][1]
+ cx2 = p[2][2]
+ p[2][3]
+ # print 'r2 ', r2, ' c2 ', cx2,',',cy2
+ # stop
+ if abs(cx1 - cx2) > edge_tolerance: # horizontal
+ sayerr("horizontal")
+ px = (p[0][10].x + p[2][11].x) / 2
+ py = (p[0][11].y + p[2][11].y) / 2
+ sx = 2 * r1 + abs(p[0][10].x - p[2][11].x)
+ sy = 2 * r1
+ else: # vertical
+ sayerr("vertical")
+ px = (p[0][10].x + p[0][11].x) / 2
+ py = (p[0][10].y + p[2][10].y) / 2
+ sx = 2 * r1
+ sy = 2 * r1 + abs(p[0][10].y - p[2][10].y)
+ p_center = (px, py, 0)
# Draft.makePoint(px,py, 0)
- wr=[]
- #print p
- #arc -> approximate shape with rectangle
- wr.append(Part.makeLine((px-sx/2, py-sy/2,0.0),(px-sx/2, py+sy/2,0.0)))
- wr.append(Part.makeLine((px-sx/2, py+sy/2,0.0),(px+sx/2, py+sy/2,0.0)))
- wr.append(Part.makeLine((px+sx/2, py+sy/2,0.0),(px+sx/2, py-sy/2,0.0)))
- wr.append(Part.makeLine((px+sx/2, py-sy/2,0.0),(px-sx/2, py-sy/2,0.0)))
-
- ps=Part.Wire(wr)
+ wr = []
+ # print p
+ # arc -> approximate shape with rectangle
+ wr.append(Part.makeLine((px - sx / 2, py - sy / 2, 0.0), (px - sx / 2, py + sy / 2, 0.0)))
+ wr.append(Part.makeLine((px - sx / 2, py + sy / 2, 0.0), (px + sx / 2, py + sy / 2, 0.0)))
+ wr.append(Part.makeLine((px + sx / 2, py + sy / 2, 0.0), (px + sx / 2, py - sy / 2, 0.0)))
+ wr.append(Part.makeLine((px + sx / 2, py - sy / 2, 0.0), (px - sx / 2, py - sy / 2, 0.0)))
+
+ ps = Part.Wire(wr)
face = Part.Face(ps)
Part.show(face)
- #stop
- shpName=FreeCAD.ActiveDocument.ActiveObject.Name
- #say( FreeCAD.ActiveDocument.ActiveObject.Label)
- shape= FreeCAD.ActiveDocument.ActiveObject.Shape
- pad_shps.append([p,p_center,shpName])
- i=1
- drl=[]
+ # stop
+ shpName = FreeCAD.ActiveDocument.ActiveObject.Name
+ # say( FreeCAD.ActiveDocument.ActiveObject.Label)
+ pad_shps.append([p, p_center, shpName])
+ i = 1
+ drl = []
for p in pad_shps:
- #print d
- point1=FreeCAD.Vector(p[1])
- #Draft.makePoint(p[1][0],p[1][1],p[1][2])
- shp=FreeCAD.ActiveDocument.getObject(p[2]).Shape
+ # print d
+ point1 = FreeCAD.Vector(p[1])
+ # Draft.makePoint(p[1][0],p[1][1],p[1][2])
+ shp = FreeCAD.ActiveDocument.getObject(p[2]).Shape
for p2 in pad_shps[i:]:
- shp2=FreeCAD.ActiveDocument.getObject(p2[2]).Shape
- #sayw(point);say(shp2.BoundBox.YLength);sayw(shp.BoundBox.YLength)
- #print shp2.isInside(point,0,True)
- point2=FreeCAD.Vector(p2[1])
- if shp2.isInside(point1,0,True):
- sayerr('pad in pad found! ')#+str(p[0]))
- #checking who is inside
+ shp2 = FreeCAD.ActiveDocument.getObject(p2[2]).Shape
+ # sayw(point);say(shp2.BoundBox.YLength);sayw(shp.BoundBox.YLength)
+ # print shp2.isInside(point,0,True)
+ point2 = FreeCAD.Vector(p2[1])
+ if shp2.isInside(point1, 0, True):
+ sayerr("pad in pad found! ") # +str(p[0]))
+ # checking who is inside
if shp2.BoundBox.YLength > shp.BoundBox.YLength:
drl.append(p[0])
else:
drl.append(p2[0])
- elif shp.isInside(point2,0,True):
- sayerr('pad in pad found! ')#+str(p2[0]))
- #checking who is inside
+ elif shp.isInside(point2, 0, True):
+ sayerr("pad in pad found! ") # +str(p2[0]))
+ # checking who is inside
if shp2.BoundBox.YLength > shp.BoundBox.YLength:
drl.append(p[0])
else:
drl.append(p2[0])
- i=i+1
- #print pad_shps
- #sayw(drl)
- testing=False #True
+ i = i + 1
+ # print pad_shps
+ # sayw(drl)
+ testing = False # True
if not testing:
for p in pad_shps:
FreeCAD.ActiveDocument.removeObject(p[2])
for d in drl:
- pads.remove(d) ## remove drls from pads
- #say(pads)
+ pads.remove(d) ## remove drls from pads
+ # say(pads)
return drl
- else:
- drl=[]
- return drl
+ return []
## return drls and pads without drls
+
+
##
+
def collect_pads(pad_list):
- #print pad_list
-
- #sort edges to form a single closed 2D shape
+ # print pad_list
+
+ # sort edges to form a single closed 2D shape
loopcounter = 0
normalized_pads = []
- #sayw((edges))
- #stop
- if (len(pad_list)==0):
+ # sayw((edges))
+ # stop
+ if len(pad_list) == 0:
sayw("no Pads found")
else:
- newPads = [];
- #sayerr(pad_list)
- for pad in (pad_list):
- #print pad
- if pad[0]=='circle':
+ newPads = []
+ # sayerr(pad_list)
+ for pad in pad_list:
+ # print pad
+ if pad[0] == "circle":
normalized_pads.append([pad])
- #pad_list.pop(i)
- npd=[]
- for pad in (pad_list):
- if pad[0]!='circle':
+ # pad_list.pop(i)
+ npd = []
+ for pad in pad_list:
+ if pad[0] != "circle":
npd.append(pad)
- pad_list=[]
- pad_list=npd
- #sayw(pad_list)
- #sayerr (len(pad_list))
- #stop
- if (len(pad_list)>0):
- #print pad_list
- #newPads.append(pad_list.pop(0))
- #print 'HERE'
- #print pad_list[0]
+ pad_list = []
+ pad_list = npd
+ # sayw(pad_list)
+ # sayerr (len(pad_list))
+ # stop
+ if len(pad_list) > 0:
+ # print pad_list
+ # newPads.append(pad_list.pop(0))
+ # print 'HERE'
+ # print pad_list[0]
## print pad_list[1][9].Radius, ' ',pad_list[1][9].Center.x,' ',pad_list[1][9].Center.y
## print pad_list[1][10].x, ' ',pad_list[1][10].y # p1.x,p1.y
## print pad_list[1][11].x, ' ',pad_list[1][11].y # p2.x,p2.y
newPads.append(pad_list[0])
pad_list.pop(0)
- #print pad_list
- if newPads[0][0]=='line':
- #print newPads,' line'#;stop
- nextCoordinate = (newPads[0][3],newPads[0][4])
- firstCoordinate = (newPads[0][1],newPads[0][2])
- elif newPads[0][0]=='arc':
- nextCoordinate = (newPads[0][10].x,newPads[0][10].y)
- firstCoordinate = (newPads[0][11].x,newPads[0][11].y)
- #elif newPads[0][0]=='circle':
+ # print pad_list
+ if newPads[0][0] == "line":
+ # print newPads,' line'#;stop
+ nextCoordinate = (newPads[0][3], newPads[0][4])
+ firstCoordinate = (newPads[0][1], newPads[0][2])
+ elif newPads[0][0] == "arc":
+ nextCoordinate = (newPads[0][10].x, newPads[0][10].y)
+ firstCoordinate = (newPads[0][11].x, newPads[0][11].y)
+ # elif newPads[0][0]=='circle':
# normalized_pads.append(newPads)
# ## TDB!!!
- #print 'nextCoordinate1 ',nextCoordinate
- #print pad_list;stop
- while(len(pad_list)>0 and loopcounter < 2):
+ # print 'nextCoordinate1 ',nextCoordinate
+ # print pad_list;stop
+ while len(pad_list) > 0 and loopcounter < 2:
loopcounter = loopcounter + 1
- #print "nextCoordinate: ", nextCoordinate
- #if len(newEdges[0].Vertexes) > 1: # not circle
+ # print "nextCoordinate: ", nextCoordinate
+ # if len(newEdges[0].Vertexes) > 1: # not circle
for j, pad in enumerate(pad_list):
- #print j
- #sayerr(pad_list[j][0])
- #say(pad)
- #print pad_list[j],' line1'#;stop
- if pad_list[j][0]=='line':
- #print pad_list[j],' line2'#;stop
- #print 'nextCoordinate ',nextCoordinate
- if distance((pad_list[j][3],pad_list[j][4]), nextCoordinate)<=edge_tolerance:
- #if edges[j].Vertexes[-1].Point != nextCoordinate:
+ # print j
+ # sayerr(pad_list[j][0])
+ # say(pad)
+ # print pad_list[j],' line1'#;stop
+ if pad[0] == "line":
+ # print pad_list[j],' line2'#;stop
+ # print 'nextCoordinate ',nextCoordinate
+ if distance((pad[3], pad[4]), nextCoordinate) <= edge_tolerance:
+ # if edges[j].Vertexes[-1].Point != nextCoordinate:
## if distance((pad_list[j][3],pad_list[j][4]), nextCoordinate)>edge_tolerance_warning:
## sayerr('non coincident edges:\n'+str(nextCoordinate)+';'+str((pad_list[j][1],pad_list[j][2])))
- nextCoordinate = (pad_list[j][1],pad_list[j][2])
+ nextCoordinate = (pad[1], pad[2])
newPads.append(pad_list.pop(j))
loopcounter = 0
break
- elif distance((pad_list[j][1],pad_list[j][2]), nextCoordinate)<=edge_tolerance:
- #if edges[j].Vertexes[0].Point != nextCoordinate:
+ if distance((pad[1], pad[2]), nextCoordinate) <= edge_tolerance:
+ # if edges[j].Vertexes[0].Point != nextCoordinate:
## if distance((pad_list[j][1],pad_list[j][2]), nextCoordinate)>edge_tolerance_warning:
## sayerr('non coincident edges:\n'+str(nextCoordinate)+';'+str((pad_list[j][3],pad_list[j][4])))
- nextCoordinate = (pad_list[j][3],pad_list[j][4])
+ nextCoordinate = (pad[3], pad[4])
newPads.append(pad_list.pop(j))
loopcounter = 0
break
- elif pad_list[j][0]=='arc':
- #print pad_list[j],' line2'#;stop
- #print 'nextCoordinate ',nextCoordinate
- if distance((pad_list[j][11].x,pad_list[j][11].y), nextCoordinate)<=edge_tolerance:
- #if edges[j].Vertexes[-1].Point != nextCoordinate:
+ elif pad[0] == "arc":
+ # print pad_list[j],' line2'#;stop
+ # print 'nextCoordinate ',nextCoordinate
+ if distance((pad[11].x, pad[11].y), nextCoordinate) <= edge_tolerance:
+ # if edges[j].Vertexes[-1].Point != nextCoordinate:
## if distance((pad_list[j][3],pad_list[j][4]), nextCoordinate)>edge_tolerance_warning:
## sayerr('non coincident edges:\n'+str(nextCoordinate)+';'+str((pad_list[j][1],pad_list[j][2])))
- nextCoordinate = (pad_list[j][10].x,pad_list[j][10].y)
+ nextCoordinate = (pad[10].x, pad[10].y)
newPads.append(pad_list.pop(j))
loopcounter = 0
break
- elif distance((pad_list[j][10].x,pad_list[j][10].y), nextCoordinate)<=edge_tolerance:
- #if edges[j].Vertexes[0].Point != nextCoordinate:
+ if distance((pad[10].x, pad[10].y), nextCoordinate) <= edge_tolerance:
+ # if edges[j].Vertexes[0].Point != nextCoordinate:
## if distance((pad_list[j][1],pad_list[j][2]), nextCoordinate)>edge_tolerance_warning:
## sayerr('non coincident edges:\n'+str(nextCoordinate)+';'+str((pad_list[j][3],pad_list[j][4])))
- nextCoordinate = (pad_list[j][11].x,pad_list[j][11].y)
+ nextCoordinate = (pad[11].x, pad[11].y)
newPads.append(pad_list.pop(j))
loopcounter = 0
break
- #elif pad_list[j][0]=='circle':
+ # elif pad_list[j][0]=='circle':
# nextCoordinate=firstCoordinate
# normalized_pads.append(newPads)
# loopcounter = 0
# break
# #print pad_list[j]
# #stop
- #sayw(len(pad_list))
- #sayw(pad_list)
- if distance(firstCoordinate, nextCoordinate)<=edge_tolerance:# or pad_list[j-1][0]=='circle':
- say('2d closed path')
+ # sayw(len(pad_list))
+ # sayw(pad_list)
+ if distance(firstCoordinate, nextCoordinate) <= edge_tolerance: # or pad_list[j-1][0]=='circle':
+ say("2d closed path")
normalized_pads.append(newPads)
- if (len(pad_list)>0):
- newPads = [];
+ if len(pad_list) > 0:
+ newPads = []
newPads.append(pad_list.pop(0))
- if newPads[0][0]=='line':
- nextCoordinate = (newPads[0][3],newPads[0][4])
- firstCoordinate = (newPads[0][1],newPads[0][2])
- elif newPads[0][0]=='arc':
- nextCoordinate = (newPads[0][11].x,newPads[0][11].y)
- firstCoordinate = (newPads[0][10].x,newPads[0][10].y)
- #stop
- #elif newPads[0][0]=='circle':
-
- #else:
+ if newPads[0][0] == "line":
+ nextCoordinate = (newPads[0][3], newPads[0][4])
+ firstCoordinate = (newPads[0][1], newPads[0][2])
+ elif newPads[0][0] == "arc":
+ nextCoordinate = (newPads[0][11].x, newPads[0][11].y)
+ firstCoordinate = (newPads[0][10].x, newPads[0][10].y)
+ # stop
+ # elif newPads[0][0]=='circle':
+
+ # else:
# say("error in creating Pads")
- # stop
- #print normalized_pads, 'pads NBR ', len(normalized_pads), 'loopcounter ', loopcounter
- #sayw('pads NBR '+str(len(normalized_pads)))
- #sayw('normalized_pads '+str((normalized_pads)))
- norm_pads=[];n_pads=[]
- #print normalized_pads
- #stop
+ # stop
+ # print normalized_pads, 'pads NBR ', len(normalized_pads), 'loopcounter ', loopcounter
+ # sayw('pads NBR '+str(len(normalized_pads)))
+ # sayw('normalized_pads '+str((normalized_pads)))
+ norm_pads = []
+ n_pads = []
+ # print normalized_pads
+ # stop
for pads in normalized_pads:
- #sayw (pads)
- if pads[0][0]=='line':
- #stop
+ # sayw (pads)
+ if pads[0][0] == "line":
+ # stop
first_elm = pads[0]
- n_pads=[];i=1
+ n_pads = []
+ i = 1
for elm in pads:
- if i>1:
+ if i > 1:
n_pads.append(elm)
- i=i+1
+ i = i + 1
n_pads.append(first_elm)
- #stop
+ # stop
norm_pads.append(n_pads)
else:
norm_pads.append(pads)
- #sayerr(norm_pads);stop
+ # sayerr(norm_pads);stop
- if len (norm_pads)>0:
- #sayw(norm_pads)
+ if len(norm_pads) > 0:
+ # sayw(norm_pads)
return norm_pads
- else:
- return normalized_pads
-
+ return normalized_pads
+ return None
+
+
##
-def createFpPad(pad,offset,tp, _drills=None):
+
+def createFpPad(pad, offset, tp, _drills=None):
global pad_nbr, edge_tolerance
import Draft
-
- #if tp=='SMD':
+
+ # if tp=='SMD':
# if pad[0]=='circle':
# sayerr('circle pad nbr.'+str(pad_nbr))
# px=pad[2];py=pad[3]*-1;sx=2*pad[1];sy=2*pad[1]
@@ -19006,366 +20418,543 @@ def createFpPad(pad,offset,tp, _drills=None):
# return pdl
# else:
# return u''
- if tp=='Drills': #getting center and size
- if pad[0]=='circle':
- sayerr('circle drill')
- px=pad[2];py=pad[3]*-1;sx=2*pad[1];sy=2*pad[1]
- drl =[px,py,sx,sy]
- pad_nbr=pad_nbr+1
- #say(drl)
+ if tp == "Drills": # getting center and size
+ if pad[0] == "circle":
+ sayerr("circle drill")
+ px = pad[2]
+ py = pad[3] * -1
+ sx = 2 * pad[1]
+ sy = 2 * pad[1]
+ drl = [px, py, sx, sy]
+ pad_nbr = pad_nbr + 1
+ # say(drl)
return drl
- elif pad[0][0]=='arc':
- sayerr('oval drill')
- #print pad
- r1=pad[0][1]; cx1=pad[0][2]; cy1=pad[0][3]
- #print 'r1 ', r1, ' c1 ', cx1,',',cy1
- r2=pad[2][1]; cx2=pad[2][2]; cy2=pad[2][3]
+ if pad[0][0] == "arc":
+ sayerr("oval drill")
+ # print pad
+ r1 = pad[0][1]
+ cx1 = pad[0][2]
+ cy1 = pad[0][3]
+ # print 'r1 ', r1, ' c1 ', cx1,',',cy1
+ r2 = pad[2][1]
+ cx2 = pad[2][2]
+ cy2 = pad[2][3]
# print 'r2 ', r2, ' c2 ', cx2,',',cy2
- #stop
+ # stop
## different method for horizontal and vertical
- if abs(cx1-cx2)>edge_tolerance: # horizontal
- px=((cx1-r1)+(cx2+r2))/2;py=((cy1-r1)+(cy2+r2))/-2;sx=abs(cx1-cx2)+2*r2;sy=2*r2
- else: #vertical
- px=((cx1-r1)+(cx2+r2))/2;py=((cy1-r1)+(cy2+r2))/-2;sx=2*r2;sy=abs(cy1-cy2)+2*r2
- drl =[px,py,sx,sy]
- pad_nbr=pad_nbr+1
- #say(pad);sayw(drl)
+ if abs(cx1 - cx2) > edge_tolerance: # horizontal
+ px = ((cx1 - r1) + (cx2 + r2)) / 2
+ py = ((cy1 - r1) + (cy2 + r2)) / -2
+ sx = abs(cx1 - cx2) + 2 * r2
+ sy = 2 * r2
+ else: # vertical
+ px = ((cx1 - r1) + (cx2 + r2)) / 2
+ py = ((cy1 - r1) + (cy2 + r2)) / -2
+ sx = 2 * r2
+ sy = abs(cy1 - cy2) + 2 * r2
+ drl = [px, py, sx, sy]
+ pad_nbr = pad_nbr + 1
+ # say(pad);sayw(drl)
return drl
- else:
- return u''
- #elif tp == 'PadsAll' or tp=='TH' or tp=='NPTH': #getting center and size
- elif 'PadsAll' in tp or tp=='TH' or tp=='NPTH': #getting center and size
- pad_layers=" (layers *.Cu *.Mask))"
- if tp=='PadsAll':
- tp='TH';ptp='thru_hole'
- if tp=='TH':
- ptp='thru_hole'
- else:
- ptp='np_thru_hole'
- #sayw (pad)
- found_drill=False
- if pad[0]=='circle':
- if '_padNbr=' in pad[-1]:
- padNbr='"'+pad[-1][pad[-1].index('_padNbr='):].replace('_padNbr=','').replace('_tmp','').replace('_','')+'"'
- elif '_padNum=' in pad[-1]:
- padNbr='"'+pad[-1][pad[-1].index('_padNum='):].replace('_padNum=','').replace('_tmp','').replace('_','')+'"'
+ return ""
+ # elif tp == 'PadsAll' or tp=='TH' or tp=='NPTH': #getting center and size
+ if "PadsAll" in tp or tp in {"TH", "NPTH"}: # getting center and size
+ pad_layers = " (layers *.Cu *.Mask))"
+ if tp == "PadsAll":
+ tp = "TH"
+ ptp = "thru_hole"
+ ptp = "thru_hole" if tp == "TH" else "np_thru_hole"
+ # sayw (pad)
+ found_drill = False
+ if pad[0] == "circle":
+ if "_padNbr=" in pad[-1]:
+ padNbr = (
+ '"'
+ + pad[-1][pad[-1].index("_padNbr=") :].replace("_padNbr=", "").replace("_tmp", "").replace("_", "")
+ + '"'
+ )
+ elif "_padNum=" in pad[-1]:
+ padNbr = (
+ '"'
+ + pad[-1][pad[-1].index("_padNum=") :].replace("_padNum=", "").replace("_tmp", "").replace("_", "")
+ + '"'
+ )
else:
- padNbr='"#"'
- sayerr('circle pad nbr.'+str(pad_nbr))
- cx=pad[2];cy=pad[3]*-1;sx=2*pad[1];sy=2*pad[1]
- if len(_drills)>0:
- #print _drills
+ padNbr = '"#"'
+ sayerr("circle pad nbr." + str(pad_nbr))
+ cx = pad[2]
+ cy = pad[3] * -1
+ sx = 2 * pad[1]
+ sy = 2 * pad[1]
+ if len(_drills) > 0:
+ # print _drills
for d in _drills:
# print d
- if d[0] > cx-sx/2 and d[0] < cx+sx/2 and d[1] > cy-sy/2 and d[1] < cy+sy/2:
- sayw('drill in pad found!')
- found_drill=True
+ if d[0] > cx - sx / 2 and d[0] < cx + sx / 2 and d[1] > cy - sy / 2 and d[1] < cy + sy / 2:
+ sayw("drill in pad found!")
+ found_drill = True
break
- #drl_size=[d[2],d[3]]
+ # drl_size=[d[2],d[3]]
### OFFSET
if found_drill:
- if d[2]!=d[3]:
- drill_str="(drill oval "+"{0:.3f}".format(d[2])+" "+"{0:.3f}".format(d[3]) #+")"
+ if d[2] != d[3]:
+ drill_str = "(drill oval " + f"{d[2]:.3f}" + " " + f"{d[3]:.3f}" # +")"
else:
- drill_str="(drill "+"{0:.3f}".format(d[2]) #+")"
- if abs(d[0]-cx)>edge_tolerance or abs(d[1]-cy)>edge_tolerance:
- #if d[0] != cx or d[1] != cy:
- drill_str=drill_str+" (offset "+"{0:.3f}".format(cx-d[0])+" "+"{0:.3f}".format(cy-d[1])+"))" #+")"
- cx=d[0];cy=d[1]
+ drill_str = "(drill " + f"{d[2]:.3f}" # +")"
+ if abs(d[0] - cx) > edge_tolerance or abs(d[1] - cy) > edge_tolerance:
+ # if d[0] != cx or d[1] != cy:
+ drill_str = (
+ drill_str + " (offset " + f"{cx - d[0]:.3f}" + " " + f"{cy - d[1]:.3f}" + "))"
+ ) # +")"
+ cx = d[0]
+ cy = d[1]
else:
- drill_str=drill_str+")"
+ drill_str = drill_str + ")"
else:
- drill_str="" #"(drill 0)"
- if tp=='NPTH':
- ptp="np_thru_hole"; pad_layers=" (layers *.Cu *.Mask))"
- drill_str="(drill "+"{0:.3f}".format(sx) +")"
- #drill_str="(drill oval "+str(d[2])+" "+str(d[3]) #"(drill 0)"
+ drill_str = "" # "(drill 0)"
+ if tp == "NPTH":
+ ptp = "np_thru_hole"
+ pad_layers = " (layers *.Cu *.Mask))"
+ drill_str = "(drill " + f"{sx:.3f}" + ")"
+ # drill_str="(drill oval "+str(d[2])+" "+str(d[3]) #"(drill 0)"
else:
- #print('pad[-1]',pad[-1])
- pattern = '_In+([0-9]*?).Cu'
+ # print('pad[-1]',pad[-1])
+ pattern = "_In+([0-9]*?).Cu"
result = re.search(pattern, pad[-1])
- if 'B_Cu' in pad[-1]:
- pdLr='B.Cu'
- ptp="smd"; pad_layers=" (layers B.Cu B.Paste B.Mask))"
+ if "B_Cu" in pad[-1]:
+ pdLr = "B.Cu"
+ ptp = "smd"
+ pad_layers = " (layers B.Cu B.Paste B.Mask))"
elif result is not None:
- pdLr=result.group().replace('_','.')[1:]
- ptp="smd"; pad_layers=" (layers "+pdLr+"))"
+ pdLr = result.group().replace("_", ".")[1:]
+ ptp = "smd"
+ pad_layers = " (layers " + pdLr + "))"
else:
- pdLr='F.Cu'
- ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
- drill_str="" #"(drill 0)"
+ pdLr = "F.Cu"
+ ptp = "smd"
+ pad_layers = " (layers F.Cu F.Paste F.Mask))"
+ drill_str = "" # "(drill 0)"
+ elif tp == "NPTH":
+ ptp = "np_thru_hole"
+ pad_layers = " (layers *.Cu *.Mask))"
+ drill_str = "(drill " + f"{sx:.3f}" + ")"
+ # drill_str="(drill oval "+str(d[2])+" "+str(d[3]) #"(drill 0)"
else:
- if tp=='NPTH':
- ptp="np_thru_hole"; pad_layers=" (layers *.Cu *.Mask))"
- drill_str="(drill "+"{0:.3f}".format(sx) +")"
- #drill_str="(drill oval "+str(d[2])+" "+str(d[3]) #"(drill 0)"
+ if 0: #'B_Cu' in tp:
+ ptp = "smd"
+ pad_layers = " (layers B.Cu B.Paste B.Mask))"
else:
- if 0: #'B_Cu' in tp:
- ptp="smd"; pad_layers=" (layers B.Cu B.Paste B.Mask))"
- else:
- ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
- drill_str="" #"(drill 0)"
- if sx==sy:
- pshp='circle'
- else:
- pshp='oval'
- #pdl =" (pad "+str(pad_nbr)+" "+ptp+" "+pshp+" (at "+str(cx)+" "+str(cy)+") (size "+str(sx)+" "+str(sy)+") "+drill_str+pad_layers
- pdl =" (pad "+padNbr+" "+ptp+" "+pshp+" (at "+"{0:.3f}".format(cx)+" "+"{0:.3f}".format(cy)+") (size "+"{0:.3f}".format(sx)+" "+"{0:.3f}".format(sy)+") "+drill_str+pad_layers
- pad_nbr=pad_nbr+1
- #say(pad)
+ ptp = "smd"
+ pad_layers = " (layers F.Cu F.Paste F.Mask))"
+ drill_str = "" # "(drill 0)"
+ pshp = "circle" if sx == sy else "oval"
+ # pdl =" (pad "+str(pad_nbr)+" "+ptp+" "+pshp+" (at "+str(cx)+" "+str(cy)+") (size "+str(sx)+" "+str(sy)+") "+drill_str+pad_layers
+ pdl = (
+ " (pad "
+ + padNbr
+ + " "
+ + ptp
+ + " "
+ + pshp
+ + " (at "
+ + f"{cx:.3f}"
+ + " "
+ + f"{cy:.3f}"
+ + ") (size "
+ + f"{sx:.3f}"
+ + " "
+ + f"{sy:.3f}"
+ + ") "
+ + drill_str
+ + pad_layers
+ )
+ pad_nbr = pad_nbr + 1
+ # say(pad)
return pdl
- elif pad[0][0]=='line':
- if '_padNbr=' in pad[0][-1]:
- padNbr='"'+pad[0][-1][pad[0][-1].index('_padNbr='):].replace('_padNbr=','').replace('_tmp','').replace('_','')+'"'
- elif '_padNum=' in pad[0][-1]:
- padNbr='"'+pad[0][-1][pad[0][-1].index('_padNum='):].replace('_padNum=','').replace('_tmp','').replace('_','')+'"'
+ if pad[0][0] == "line":
+ if "_padNbr=" in pad[0][-1]:
+ padNbr = (
+ '"'
+ + pad[0][-1][pad[0][-1].index("_padNbr=") :]
+ .replace("_padNbr=", "")
+ .replace("_tmp", "")
+ .replace("_", "")
+ + '"'
+ )
+ elif "_padNum=" in pad[0][-1]:
+ padNbr = (
+ '"'
+ + pad[0][-1][pad[0][-1].index("_padNum=") :]
+ .replace("_padNum=", "")
+ .replace("_tmp", "")
+ .replace("_", "")
+ + '"'
+ )
else:
- padNbr='"#"'
- #say(_drills)
- #sayerr('rect pad nbr.'+str(pad_nbr))
- #sayw(str(pad))
- #cx=(pad[0][1]+pad[0][3])/2;cy=(pad[1][2]+pad[1][4])/-2;sx=abs(pad[0][1]-pad[0][3]);sy=abs(pad[1][2]-pad[1][4])
- ptype="rect"
- sayerr('rect pad nbr.'+str(pad_nbr))
- px=(pad[0][1]+pad[0][3])/2;py=(pad[1][2]+pad[1][4])/-2;
- if abs(pad[0][1]-pad[0][3]) > edge_tolerance:
- sx=abs(pad[0][1]-pad[0][3])
- px=(pad[0][1]+pad[0][3])/2
+ padNbr = '"#"'
+ # say(_drills)
+ # sayerr('rect pad nbr.'+str(pad_nbr))
+ # sayw(str(pad))
+ # cx=(pad[0][1]+pad[0][3])/2;cy=(pad[1][2]+pad[1][4])/-2;sx=abs(pad[0][1]-pad[0][3]);sy=abs(pad[1][2]-pad[1][4])
+ ptype = "rect"
+ sayerr("rect pad nbr." + str(pad_nbr))
+ px = (pad[0][1] + pad[0][3]) / 2
+ py = (pad[1][2] + pad[1][4]) / -2
+ if abs(pad[0][1] - pad[0][3]) > edge_tolerance:
+ sx = abs(pad[0][1] - pad[0][3])
+ px = (pad[0][1] + pad[0][3]) / 2
else:
- sx=abs(pad[1][1]-pad[1][3])
- px=(pad[1][1]+pad[1][3])/2
- if abs(pad[1][2]-pad[1][4]) > edge_tolerance:
- sy=abs(pad[1][2]-pad[1][4])
- py=(pad[1][2]+pad[1][4])/-2;
+ sx = abs(pad[1][1] - pad[1][3])
+ px = (pad[1][1] + pad[1][3]) / 2
+ if abs(pad[1][2] - pad[1][4]) > edge_tolerance:
+ sy = abs(pad[1][2] - pad[1][4])
+ py = (pad[1][2] + pad[1][4]) / -2
else:
- sy=abs(pad[0][2]-pad[0][4])
- py=(pad[0][2]+pad[0][4])/-2;
- #print pad[0];print pad[1]
- #stop
- found_drill=False
- if len(_drills)>0:
+ sy = abs(pad[0][2] - pad[0][4])
+ py = (pad[0][2] + pad[0][4]) / -2
+ # print pad[0];print pad[1]
+ # stop
+ found_drill = False
+ if len(_drills) > 0:
for d in _drills:
- if d[0] > px-sx/2 and d[0] < px+sx/2 and d[1] > py-sy/2 and d[1] < py+sy/2:
- sayw('drill in pad found! '+str(d[0])+','+str(d[1])+'/'+str(px)+','+str(py)+':'+str(sx)+','+str(sy))
- found_drill=True
+ if d[0] > px - sx / 2 and d[0] < px + sx / 2 and d[1] > py - sy / 2 and d[1] < py + sy / 2:
+ sayw(
+ "drill in pad found! "
+ + str(d[0])
+ + ","
+ + str(d[1])
+ + "/"
+ + str(px)
+ + ","
+ + str(py)
+ + ":"
+ + str(sx)
+ + ","
+ + str(sy),
+ )
+ found_drill = True
break
- #drl_size=[d[2],d[3]]
+ # drl_size=[d[2],d[3]]
### OFFSET
if found_drill:
- if d[2]!=d[3]:
- drill_str="(drill oval "+"{0:.3f}".format(d[2])+" "+"{0:.3f}".format(d[3]) #+")"
+ if d[2] != d[3]:
+ drill_str = "(drill oval " + f"{d[2]:.3f}" + " " + f"{d[3]:.3f}" # +")"
else:
- drill_str="(drill "+"{0:.3f}".format(d[2]) #+")"
- if abs(d[0]-px)>edge_tolerance or abs(d[1]-py)>edge_tolerance:
- drill_str=drill_str+" (offset "+"{0:.3f}".format(px-d[0])+" "+"{0:.3f}".format(py-d[1])+"))" #+")"
- px=d[0];py=d[1]
+ drill_str = "(drill " + f"{d[2]:.3f}" # +")"
+ if abs(d[0] - px) > edge_tolerance or abs(d[1] - py) > edge_tolerance:
+ drill_str = (
+ drill_str + " (offset " + f"{px - d[0]:.3f}" + " " + f"{py - d[1]:.3f}" + "))"
+ ) # +")"
+ px = d[0]
+ py = d[1]
else:
- drill_str=drill_str+")"
+ drill_str = drill_str + ")"
else:
- drill_str="" #"(drill 0)"
- if tp=='NPTH':
- sayerr('Error: NPTH rectangular pad WITHOUT drill -> correcting to oval/circle pad')
- ptp="np_thru_hole"; pad_layers=" (layers *.Cu *.Mask))"
- if sx==sy:
- drill_str="(drill "+"{0:.3f}".format(sx) +")"
- ptype="circle"
+ drill_str = "" # "(drill 0)"
+ if tp == "NPTH":
+ sayerr("Error: NPTH rectangular pad WITHOUT drill -> correcting to oval/circle pad")
+ ptp = "np_thru_hole"
+ pad_layers = " (layers *.Cu *.Mask))"
+ if sx == sy:
+ drill_str = "(drill " + f"{sx:.3f}" + ")"
+ ptype = "circle"
else:
- drill_str="(drill oval "+"{0:.3f}".format(sx)+" "+"{0:.3f}".format(sy)+")" #"(drill 0)"
- ptype="oval"
+ drill_str = "(drill oval " + f"{sx:.3f}" + " " + f"{sy:.3f}" + ")" # "(drill 0)"
+ ptype = "oval"
else:
- #print('pad[-1] Rect',pad[-1])
- pattern = '_In+([0-9]*?).Cu'
+ # print('pad[-1] Rect',pad[-1])
+ pattern = "_In+([0-9]*?).Cu"
result = re.search(pattern, pad[0][-1])
- if 'B_Cu' in pad[0][-1]:
- pdLr='B.Cu'
- ptp="smd"; pad_layers=" (layers B.Cu B.Paste B.Mask))"
+ if "B_Cu" in pad[0][-1]:
+ pdLr = "B.Cu"
+ ptp = "smd"
+ pad_layers = " (layers B.Cu B.Paste B.Mask))"
elif result is not None:
- pdLr=result.group().replace('_','.')[1:]
- ptp="smd"; pad_layers=" (layers "+pdLr+"))"
+ pdLr = result.group().replace("_", ".")[1:]
+ ptp = "smd"
+ pad_layers = " (layers " + pdLr + "))"
else:
- pdLr='F.Cu'
- ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
- #ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
- #drill_str="" #"(drill 0)"
+ pdLr = "F.Cu"
+ ptp = "smd"
+ pad_layers = " (layers F.Cu F.Paste F.Mask))"
+ # ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
+ # drill_str="" #"(drill 0)"
+ elif tp == "NPTH":
+ ptp = "np_thru_hole"
+ pad_layers = " (layers *.Cu *.Mask))"
+ if sx == sy:
+ drill_str = "(drill " + f"{sx:.3f}" + ")"
+ ptype = "circle"
+ else:
+ drill_str = "(drill oval " + f"{sx:.3f}" + " " + f"{sy:.3f}" + ")" # "(drill 0)"
+ ptype = "oval"
else:
- if tp=='NPTH':
- ptp="np_thru_hole"; pad_layers=" (layers *.Cu *.Mask))"
- if sx==sy:
- drill_str="(drill "+"{0:.3f}".format(sx) +")"
- ptype="circle"
- else:
- drill_str="(drill oval "+"{0:.3f}".format(sx)+" "+"{0:.3f}".format(sy)+")" #"(drill 0)"
- ptype="oval"
+ # print('pad[-1] Rect 2',pad[-1])
+ pattern = "_In+([0-9]*?).Cu"
+ result = re.search(pattern, pad[0][-1])
+ if "B_Cu" in pad[0][-1]:
+ pdLr = "B.Cu"
+ ptp = "smd"
+ pad_layers = " (layers B.Cu B.Paste B.Mask))"
+ elif result is not None:
+ pdLr = result.group().replace("_", ".")[1:]
+ ptp = "smd"
+ pad_layers = " (layers " + pdLr + "))"
else:
- #print('pad[-1] Rect 2',pad[-1])
- pattern = '_In+([0-9]*?).Cu'
- result = re.search(pattern, pad[0][-1])
- if 'B_Cu' in pad[0][-1]:
- pdLr='B.Cu'
- ptp="smd"; pad_layers=" (layers B.Cu B.Paste B.Mask))"
- elif result is not None:
- pdLr=result.group().replace('_','.')[1:]
- ptp="smd"; pad_layers=" (layers "+pdLr+"))"
- else:
- pdLr='F.Cu'
- ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
- #ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
- drill_str="" #"(drill 0)"
-
- #pdl =" (pad "+str(pad_nbr)+" "+ptp+" rect (at "+str(px)+" "+str(py)+") (size "+str(sx)+" "+str(sy)+") "+drill_str+pad_layers
- pdl =" (pad "+padNbr+" "+ptp+" "+ptype+" (at "+"{0:.3f}".format(px)+" "+"{0:.3f}".format(py)+") (size "+"{0:.3f}".format(sx)+" "+"{0:.3f}".format(sy)+") "+drill_str+pad_layers
- #pdl =" (pad "+str(pad_nbr)+" thru_hole rect (at "+str(px)+" "+str(py)+") (size "+str(sx)+" "+str(sy)+") (layers F.Cu F.Paste F.Mask))"
- pad_nbr=pad_nbr+1
- #say(pad);sayw(pdl)
+ pdLr = "F.Cu"
+ ptp = "smd"
+ pad_layers = " (layers F.Cu F.Paste F.Mask))"
+ # ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
+ drill_str = "" # "(drill 0)"
+
+ # pdl =" (pad "+str(pad_nbr)+" "+ptp+" rect (at "+str(px)+" "+str(py)+") (size "+str(sx)+" "+str(sy)+") "+drill_str+pad_layers
+ pdl = (
+ " (pad "
+ + padNbr
+ + " "
+ + ptp
+ + " "
+ + ptype
+ + " (at "
+ + f"{px:.3f}"
+ + " "
+ + f"{py:.3f}"
+ + ") (size "
+ + f"{sx:.3f}"
+ + " "
+ + f"{sy:.3f}"
+ + ") "
+ + drill_str
+ + pad_layers
+ )
+ # pdl =" (pad "+str(pad_nbr)+" thru_hole rect (at "+str(px)+" "+str(py)+") (size "+str(sx)+" "+str(sy)+") (layers F.Cu F.Paste F.Mask))"
+ pad_nbr = pad_nbr + 1
+ # say(pad);sayw(pdl)
return pdl
- elif pad[0][0]=='arc':
- if '_padNbr=' in pad[0][-1]:
- padNbr='"'+pad[0][-1][pad[0][-1].index('_padNbr='):].replace('_padNbr=','').replace('_tmp','').replace('_','')+'"'
- elif '_padNum=' in pad[0][-1]:
- padNbr='"'+pad[0][-1][pad[0][-1].index('_padNum='):].replace('_padNum=','').replace('_tmp','').replace('_','')+'"'
+ if pad[0][0] == "arc":
+ if "_padNbr=" in pad[0][-1]:
+ padNbr = (
+ '"'
+ + pad[0][-1][pad[0][-1].index("_padNbr=") :]
+ .replace("_padNbr=", "")
+ .replace("_tmp", "")
+ .replace("_", "")
+ + '"'
+ )
+ elif "_padNum=" in pad[0][-1]:
+ padNbr = (
+ '"'
+ + pad[0][-1][pad[0][-1].index("_padNum=") :]
+ .replace("_padNum=", "")
+ .replace("_tmp", "")
+ .replace("_", "")
+ + '"'
+ )
else:
- padNbr='"#"'
- sayerr('arc pad nbr.'+str(pad_nbr))
- #print pad
- r1=pad[0][1]; cx1=pad[0][2]; cy1=pad[0][3]
- #print 'r1 ', r1, ' c1 ', cx1,',',cy1
- r2=pad[2][1]; cx2=pad[2][2]; cy2=pad[2][3]
- #print 'r2 ', r2, ' c2 ', cx2,',',cy2
- #stop
- if abs(cx1-cx2)>edge_tolerance: # horizontal
- sayerr('horizontal')
- px=(pad[0][10].x+pad[2][11].x)/2;py=(pad[0][11].y+pad[2][11].y)/-2;
- sx=2*r1+abs((pad[0][10].x-pad[2][11].x)); sy=2*r1
- else: #vertical
- sayerr('vertical')
- px=(pad[0][10].x+pad[0][11].x)/2;py=(pad[0][10].y+pad[2][10].y)/-2;
- sx=2*r1; sy=2*r1+abs((pad[0][10].y-pad[2][10].y))
-
- found_drill=False
- if len(_drills)>0:
+ padNbr = '"#"'
+ sayerr("arc pad nbr." + str(pad_nbr))
+ # print pad
+ r1 = pad[0][1]
+ cx1 = pad[0][2]
+ cy1 = pad[0][3]
+ # print 'r1 ', r1, ' c1 ', cx1,',',cy1
+ r2 = pad[2][1]
+ cx2 = pad[2][2]
+ cy2 = pad[2][3]
+ # print 'r2 ', r2, ' c2 ', cx2,',',cy2
+ # stop
+ if abs(cx1 - cx2) > edge_tolerance: # horizontal
+ sayerr("horizontal")
+ px = (pad[0][10].x + pad[2][11].x) / 2
+ py = (pad[0][11].y + pad[2][11].y) / -2
+ sx = 2 * r1 + abs(pad[0][10].x - pad[2][11].x)
+ sy = 2 * r1
+ else: # vertical
+ sayerr("vertical")
+ px = (pad[0][10].x + pad[0][11].x) / 2
+ py = (pad[0][10].y + pad[2][10].y) / -2
+ sx = 2 * r1
+ sy = 2 * r1 + abs(pad[0][10].y - pad[2][10].y)
+
+ found_drill = False
+ if len(_drills) > 0:
for d in _drills:
- if d[0] > px-sx/2 and d[0] < px+sx/2 and d[1] > py-sy/2 and d[1] < py+sy/2:
- sayw('drill in pad found! '+str(d[0])+','+str(d[1])+'/'+str(px)+','+str(py)+':'+str(sx)+','+str(sy))
- #if d[0] > cx-sx/2 and d[0] < cx+sx/2 and d[1] > cy-sy/2 and d[1] < cy+sy/2:
- # sayw('drill in pad found!')
- found_drill=True
+ if d[0] > px - sx / 2 and d[0] < px + sx / 2 and d[1] > py - sy / 2 and d[1] < py + sy / 2:
+ sayw(
+ "drill in pad found! "
+ + str(d[0])
+ + ","
+ + str(d[1])
+ + "/"
+ + str(px)
+ + ","
+ + str(py)
+ + ":"
+ + str(sx)
+ + ","
+ + str(sy),
+ )
+ # if d[0] > cx-sx/2 and d[0] < cx+sx/2 and d[1] > cy-sy/2 and d[1] < cy+sy/2:
+ # sayw('drill in pad found!')
+ found_drill = True
break
- #drl_size=[d[2],d[3]]
+ # drl_size=[d[2],d[3]]
### OFFSET
if found_drill:
- if d[2]!=d[3]:
- drill_str="(drill oval "+"{0:.3f}".format(d[2])+" "+"{0:.3f}".format(d[3]) #+")"
- else:
- drill_str="(drill "+"{0:.3f}".format(d[2]) #+")"
- if abs(d[0]-px)>edge_tolerance or abs(d[1]-py)>edge_tolerance:
- drill_str=drill_str+" (offset "+"{0:.3f}".format(px-d[0])+" "+"{0:.3f}".format(py-d[1])+"))" #+")"
- px=d[0];py=d[1]
+ if d[2] != d[3]:
+ drill_str = "(drill oval " + f"{d[2]:.3f}" + " " + f"{d[3]:.3f}" # +")"
else:
- drill_str=drill_str+")"
- else:
- if tp=='NPTH':
- ptp="np_thru_hole"; pad_layers=" (layers *.Cu *.Mask))"
- if sx==sy:
- drill_str="(drill "+"{0:.3f}".format(sx) +")"
- else:
- drill_str="(drill oval "+"{0:.3f}".format(sx)+" "+"{0:.3f}".format(sy)+")" #"(drill 0)"
- #drill_str="(drill oval "+str(d[2])+" "+str(d[3]) #"(drill 0)"
+ drill_str = "(drill " + f"{d[2]:.3f}" # +")"
+ if abs(d[0] - px) > edge_tolerance or abs(d[1] - py) > edge_tolerance:
+ drill_str = (
+ drill_str + " (offset " + f"{px - d[0]:.3f}" + " " + f"{py - d[1]:.3f}" + "))"
+ ) # +")"
+ px = d[0]
+ py = d[1]
else:
- pattern = '_In+([0-9]*?).Cu'
- result = re.search(pattern, pad[0][-1])
- if 'B_Cu' in pad[0][-1]:
- pdLr='B.Cu'
- ptp="smd"; pad_layers=" (layers B.Cu B.Paste B.Mask))"
- elif result is not None:
- pdLr=result.group().replace('_','.')[1:]
- ptp="smd"; pad_layers=" (layers "+pdLr+"))"
- else:
- pdLr='F.Cu'
- ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
- if '_padNbr=' in pad[0][-1]:
- padNbr='"'+pad[0][-1][pad[0][-1].index('_padNbr='):].replace('_padNbr=','')+'"'
- elif '_padNum=' in pad[0][-1]:
- padNbr='"'+pad[0][-1][pad[0][-1].index('_padNum='):].replace('_padNum=','')+'"'
- else:
- padNbr='"#"'
- #ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
- drill_str="" #"(drill 0)"
- else:
- if tp=='NPTH':
- ptp="np_thru_hole"; pad_layers=" (layers *.Cu *.Mask))"
- if sx==sy:
- drill_str="(drill "+"{0:.3f}".format(sx) +")"
+ drill_str = drill_str + ")"
+ elif tp == "NPTH":
+ ptp = "np_thru_hole"
+ pad_layers = " (layers *.Cu *.Mask))"
+ if sx == sy:
+ drill_str = "(drill " + f"{sx:.3f}" + ")"
else:
- drill_str="(drill oval "+"{0:.3f}".format(sx)+" "+"{0:.3f}".format(sy)+")" #"(drill 0)"
- #drill_str="(drill oval "+str(d[2])+" "+str(d[3]) #"(drill 0)"
+ drill_str = "(drill oval " + f"{sx:.3f}" + " " + f"{sy:.3f}" + ")" # "(drill 0)"
+ # drill_str="(drill oval "+str(d[2])+" "+str(d[3]) #"(drill 0)"
else:
- pattern = '_In+([0-9]*?).Cu'
+ pattern = "_In+([0-9]*?).Cu"
result = re.search(pattern, pad[0][-1])
- if 'B_Cu' in pad[0][-1]:
- pdLr='B.Cu'
- ptp="smd"; pad_layers=" (layers B.Cu B.Paste B.Mask))"
+ if "B_Cu" in pad[0][-1]:
+ pdLr = "B.Cu"
+ ptp = "smd"
+ pad_layers = " (layers B.Cu B.Paste B.Mask))"
elif result is not None:
- pdLr=result.group().replace('_','.')[1:]
- ptp="smd"; pad_layers=" (layers "+pdLr+"))"
+ pdLr = result.group().replace("_", ".")[1:]
+ ptp = "smd"
+ pad_layers = " (layers " + pdLr + "))"
+ else:
+ pdLr = "F.Cu"
+ ptp = "smd"
+ pad_layers = " (layers F.Cu F.Paste F.Mask))"
+ if "_padNbr=" in pad[0][-1]:
+ padNbr = '"' + pad[0][-1][pad[0][-1].index("_padNbr=") :].replace("_padNbr=", "") + '"'
+ elif "_padNum=" in pad[0][-1]:
+ padNbr = '"' + pad[0][-1][pad[0][-1].index("_padNum=") :].replace("_padNum=", "") + '"'
else:
- pdLr='F.Cu'
- ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
- #ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
- drill_str="" #"(drill 0)"
-
- #pdl =" (pad "+str(pad_nbr)+" "+ptp+" oval (at "+str(px)+" "+str(py)+") (size "+str(sx)+" "+str(sy)+") "+drill_str+pad_layers
- pdl =" (pad "+padNbr+" "+ptp+" oval (at "+"{0:.3f}".format(px)+" "+"{0:.3f}".format(py)+") (size "+"{0:.3f}".format(sx)+" "+"{0:.3f}".format(sy)+") "+drill_str+pad_layers
- #pdl =" (pad "+str(pad_nbr)+" "+ptp+" oval (at "+str(cx)+" "+str(cy)+") (size "+str(sx)+" "+str(sy)+") (layers F.Cu F.Paste F.Mask))"
- pad_nbr=pad_nbr+1
- #say(pad);sayw(pdl)
+ padNbr = '"#"'
+ # ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
+ drill_str = "" # "(drill 0)"
+ elif tp == "NPTH":
+ ptp = "np_thru_hole"
+ pad_layers = " (layers *.Cu *.Mask))"
+ if sx == sy:
+ drill_str = "(drill " + f"{sx:.3f}" + ")"
+ else:
+ drill_str = "(drill oval " + f"{sx:.3f}" + " " + f"{sy:.3f}" + ")" # "(drill 0)"
+ # drill_str="(drill oval "+str(d[2])+" "+str(d[3]) #"(drill 0)"
+ else:
+ pattern = "_In+([0-9]*?).Cu"
+ result = re.search(pattern, pad[0][-1])
+ if "B_Cu" in pad[0][-1]:
+ pdLr = "B.Cu"
+ ptp = "smd"
+ pad_layers = " (layers B.Cu B.Paste B.Mask))"
+ elif result is not None:
+ pdLr = result.group().replace("_", ".")[1:]
+ ptp = "smd"
+ pad_layers = " (layers " + pdLr + "))"
+ else:
+ pdLr = "F.Cu"
+ ptp = "smd"
+ pad_layers = " (layers F.Cu F.Paste F.Mask))"
+ # ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask))"
+ drill_str = "" # "(drill 0)"
+
+ # pdl =" (pad "+str(pad_nbr)+" "+ptp+" oval (at "+str(px)+" "+str(py)+") (size "+str(sx)+" "+str(sy)+") "+drill_str+pad_layers
+ pdl = (
+ " (pad "
+ + padNbr
+ + " "
+ + ptp
+ + " oval (at "
+ + f"{px:.3f}"
+ + " "
+ + f"{py:.3f}"
+ + ") (size "
+ + f"{sx:.3f}"
+ + " "
+ + f"{sy:.3f}"
+ + ") "
+ + drill_str
+ + pad_layers
+ )
+ # pdl =" (pad "+str(pad_nbr)+" "+ptp+" oval (at "+str(cx)+" "+str(cy)+") (size "+str(sx)+" "+str(sy)+") (layers F.Cu F.Paste F.Mask))"
+ pad_nbr = pad_nbr + 1
+ # say(pad);sayw(pdl)
return pdl
- else:
- return u''
+ return ""
##--------------------------------------------##
- #elif tp=='RoundRect':
- elif 'RoundRect' in tp:
- if '_padNbr=' in pad[0][-1]:
- padNbr='"'+pad[0][-1][pad[0][-1].index('_padNbr='):].replace('_padNbr=','').replace('_tmp','').replace('_','')+'"'
- elif '_padNum=' in pad[0][-1]:
- padNbr='"'+pad[0][-1][pad[0][-1].index('_padNum='):].replace('_padNum=','').replace('_tmp','').replace('_','')+'"'
+ # elif tp=='RoundRect':
+ if "RoundRect" in tp:
+ if "_padNbr=" in pad[0][-1]:
+ padNbr = (
+ '"'
+ + pad[0][-1][pad[0][-1].index("_padNbr=") :]
+ .replace("_padNbr=", "")
+ .replace("_tmp", "")
+ .replace("_", "")
+ + '"'
+ )
+ elif "_padNum=" in pad[0][-1]:
+ padNbr = (
+ '"'
+ + pad[0][-1][pad[0][-1].index("_padNum=") :]
+ .replace("_padNum=", "")
+ .replace("_tmp", "")
+ .replace("_", "")
+ + '"'
+ )
else:
- padNbr='"#"'
- found_drill=False
- #sayw(pad)
- #stop
- ptp='thru_hole'
- pad_layers=" (layers *.Cu *.Mask)"
- if pad[0][0]=='arc':
- #say(_drills)
- sayerr('round rect pad nbr.'+str(pad_nbr))
- #print p
- r1=pad[0][1]; cx1=pad[0][2]; cy1=pad[0][3]
- #print 'r1 ', r1, ' c1 ', cx1,',',cy1
- r2=pad[4][1]; cx2=pad[4][2]; cy2=pad[2][3]
- #print 'r2 ', r2, ' c2 ', cx2,',',cy2
- #stop
- if abs(cx1-cx2)>edge_tolerance: # horizontal
- sayerr('horizontal')
- #print pad
- px=(pad[0][10].x+pad[4][10].x)/2;
- py=(pad[0][10].y+pad[4][10].y)/2;
- sx=abs(pad[5][1]-pad[1][1])
- sy=abs(pad[7][2]-pad[3][2])
- #print r1,' ',sx-2*r1
- else: #vertical
+ padNbr = '"#"'
+ found_drill = False
+ # sayw(pad)
+ # stop
+ ptp = "thru_hole"
+ pad_layers = " (layers *.Cu *.Mask)"
+ if pad[0][0] == "arc":
+ # say(_drills)
+ sayerr("round rect pad nbr." + str(pad_nbr))
+ # print p
+ r1 = pad[0][1]
+ cx1 = pad[0][2]
+ cy1 = pad[0][3]
+ # print 'r1 ', r1, ' c1 ', cx1,',',cy1
+ r2 = pad[4][1]
+ cx2 = pad[4][2]
+ cy2 = pad[2][3]
+ # print 'r2 ', r2, ' c2 ', cx2,',',cy2
+ # stop
+ if abs(cx1 - cx2) > edge_tolerance: # horizontal
+ sayerr("horizontal")
+ # print pad
+ px = (pad[0][10].x + pad[4][10].x) / 2
+ py = (pad[0][10].y + pad[4][10].y) / 2
+ sx = abs(pad[5][1] - pad[1][1])
+ sy = abs(pad[7][2] - pad[3][2])
+ # print r1,' ',sx-2*r1
+ else: # vertical
stop
# sayerr('vertical')
# #print pad[0][10].x
# #print pad[2][10].x
# px=(pad[0][10].x+pad[4][10].x)/2;
# py=(pad[0][10].y+pad[4][10].y)/2;
- # sx=2*r1+abs(pad[3][1]-pad[3][3]);
+ # sx=2*r1+abs(pad[3][1]-pad[3][3]);
# sy=2*r1+abs(pad[1][2]-pad[1][4])
- p_center=(px,py,0)
- #print px,' ',py
- #print sx,' ',sy
- rratio=r1/min(sx,sy)
- #Draft.makePoint(px,py, 0)
+ # print px,' ',py
+ # print sx,' ',sy
+ rratio = r1 / min(sx, sy)
+ # Draft.makePoint(px,py, 0)
# cx=(pad[0][1]+pad[0][3])/2;cy=(pad[1][2]+pad[1][4])/-2;sx=abs(pad[0][1]-pad[0][3])+2*pad[4][1];sy=abs(pad[1][2]-pad[1][4])+2*pad[4][1]
# r=pad[4][1]
# rratio=r/min(sx,sy)
@@ -19384,59 +20973,81 @@ def createFpPad(pad,offset,tp, _drills=None):
# sayerr('vertical')
# px=(pad[0][10].x+pad[0][11].x)/2;py=(pad[0][10].y+pad[2][10].y)/-2;
# sx=2*r1; sy=2*r1+abs((pad[0][10].y-pad[2][10].y))
-
- found_drill=False
- if len(_drills)>0:
+
+ found_drill = False
+ if len(_drills) > 0:
for d in _drills:
- #sayw(d)
- if d[0] > px-sx/2 and d[0] < px+sx/2 and -d[1] > py-sy/2 and -d[1] < py+sy/2:
- sayw('drill in pad found! '+str(d[0])+','+str(-d[1])+'/'+str(px)+','+str(py)+':'+str(sx)+','+str(sy))
- #if d[0] > cx-sx/2 and d[0] < cx+sx/2 and d[1] > cy-sy/2 and d[1] < cy+sy/2:
- # sayw('drill in pad found!')
- found_drill=True
+ # sayw(d)
+ if d[0] > px - sx / 2 and d[0] < px + sx / 2 and -d[1] > py - sy / 2 and -d[1] < py + sy / 2:
+ sayw(
+ "drill in pad found! "
+ + str(d[0])
+ + ","
+ + str(-d[1])
+ + "/"
+ + str(px)
+ + ","
+ + str(py)
+ + ":"
+ + str(sx)
+ + ","
+ + str(sy),
+ )
+ # if d[0] > cx-sx/2 and d[0] < cx+sx/2 and d[1] > cy-sy/2 and d[1] < cy+sy/2:
+ # sayw('drill in pad found!')
+ found_drill = True
break
- #drl_size=[d[2],d[3]]
+ # drl_size=[d[2],d[3]]
### OFFSET
if found_drill:
- if d[2]!=d[3]:
- drill_str="(drill oval "+"{0:.3f}".format(abs(d[2]))+" "+"{0:.3f}".format(abs(d[3])) #+")"
+ if d[2] != d[3]:
+ drill_str = "(drill oval " + f"{abs(d[2]):.3f}" + " " + f"{abs(d[3]):.3f}" # +")"
else:
- drill_str="(drill "+"{0:.3f}".format(abs(d[2])) #+")"
- if abs(d[0]-px)>edge_tolerance or abs(-d[1]-py)>edge_tolerance:
- drill_str=drill_str+" (offset "+"{0:.3f}".format(px-d[0])+" "+"{0:.3f}".format(-py-d[1])+"))" #+")"
- px=d[0];py=d[1]
+ drill_str = "(drill " + f"{abs(d[2]):.3f}" # +")"
+ if abs(d[0] - px) > edge_tolerance or abs(-d[1] - py) > edge_tolerance:
+ drill_str = (
+ drill_str + " (offset " + f"{px - d[0]:.3f}" + " " + f"{-py - d[1]:.3f}" + "))"
+ ) # +")"
+ px = d[0]
+ py = d[1]
else:
- drill_str=drill_str+")"
+ drill_str = drill_str + ")"
else:
- pattern = '_In+([0-9]*?).Cu'
+ pattern = "_In+([0-9]*?).Cu"
result = re.search(pattern, pad[0][-1])
- if 'B_Cu' in pad[0][-1]:
- pdLr='B.Cu'
- ptp="smd"; pad_layers=" (layers B.Cu B.Paste B.Mask)"
+ if "B_Cu" in pad[0][-1]:
+ pdLr = "B.Cu"
+ ptp = "smd"
+ pad_layers = " (layers B.Cu B.Paste B.Mask)"
elif result is not None:
- pdLr=result.group().replace('_','.')[1:]
- ptp="smd"; pad_layers=" (layers "+pdLr+")"
+ pdLr = result.group().replace("_", ".")[1:]
+ ptp = "smd"
+ pad_layers = " (layers " + pdLr + ")"
else:
- pdLr='F.Cu'
- ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask)"
- #ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask)"
- py=-py
- drill_str="" #"(drill 0)"
+ pdLr = "F.Cu"
+ ptp = "smd"
+ pad_layers = " (layers F.Cu F.Paste F.Mask)"
+ # ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask)"
+ py = -py
+ drill_str = "" # "(drill 0)"
else:
- pattern = '_In+([0-9]*?).Cu'
+ pattern = "_In+([0-9]*?).Cu"
result = re.search(pattern, pad[0][-1])
- if 'B_Cu' in pad[0][-1]:
- pdLr='B.Cu'
- ptp="smd"; pad_layers=" (layers B.Cu B.Paste B.Mask)"
+ if "B_Cu" in pad[0][-1]:
+ pdLr = "B.Cu"
+ ptp = "smd"
+ pad_layers = " (layers B.Cu B.Paste B.Mask)"
elif result is not None:
- pdLr=result.group().replace('_','.')[1:]
- ptp="smd"; pad_layers=" (layers "+pdLr+")"
+ pdLr = result.group().replace("_", ".")[1:]
+ ptp = "smd"
+ pad_layers = " (layers " + pdLr + ")"
else:
- pdLr='F.Cu'
- ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask)"
- #ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask)"
- py=-py
- drill_str="" #"(drill 0)"
+ pdLr = "F.Cu"
+ ptp = "smd"
+ pad_layers = " (layers F.Cu F.Paste F.Mask)"
+ # ptp="smd"; pad_layers=" (layers F.Cu F.Paste F.Mask)"
+ py = -py
+ drill_str = "" # "(drill 0)"
# if len(_drills)>0:
# for d in _drills:
@@ -19468,16 +21079,35 @@ def createFpPad(pad,offset,tp, _drills=None):
# drill_str=""
# ptp='smd'
# p_layers='(layers F.Cu F.Paste F.Mask)'
- #rratio=0.25 ### TBD
- #pdl =" (pad "+str(pad_nbr)+" "+ptp+" roundrect (at "+str(cx)+" "+str(cy)+") (size "+\
- pdl =" (pad "+padNbr+" "+ptp+" roundrect (at "+"{0:.3f}".format(px)+" "+"{0:.3f}".format(py)+") (size "+\
- "{0:.3f}".format(sx)+" "+"{0:.3f}".format(sy)+") "+drill_str+" "+pad_layers+" (roundrect_rratio "+"{0:.3f}".format(rratio)+"))" #+str(rratio)+"))"
- #pdl =" (pad "+str(pad_nbr)+" thru_hole rect (at "+str(px)+" "+str(py)+") (size "+str(sx)+" "+str(sy)+") (layers F.Cu F.Paste F.Mask))"
- pad_nbr=pad_nbr+1
- #say(pad);sayw(pdl)
+ # rratio=0.25 ### TBD
+ # pdl =" (pad "+str(pad_nbr)+" "+ptp+" roundrect (at "+str(cx)+" "+str(cy)+") (size "+\
+ pdl = (
+ " (pad "
+ + padNbr
+ + " "
+ + ptp
+ + " roundrect (at "
+ + f"{px:.3f}"
+ + " "
+ + f"{py:.3f}"
+ + ") (size "
+ + f"{sx:.3f}"
+ + " "
+ + f"{sy:.3f}"
+ + ") "
+ + drill_str
+ + " "
+ + pad_layers
+ + " (roundrect_rratio "
+ + f"{rratio:.3f}"
+ + "))"
+ ) # +str(rratio)+"))"
+ # pdl =" (pad "+str(pad_nbr)+" thru_hole rect (at "+str(px)+" "+str(py)+") (size "+str(sx)+" "+str(sy)+") (layers F.Cu F.Paste F.Mask))"
+ pad_nbr = pad_nbr + 1
+ # say(pad);sayw(pdl)
return pdl
##--------------------------------------------##
- #elif tp=='RoundRect':
+ # elif tp=='RoundRect':
# found_drill=False
# if pad[0][0]=='line':
# #say(_drills)
@@ -19525,79 +21155,123 @@ def createFpPad(pad,offset,tp, _drills=None):
# #say(pad);sayw(pdl)
# return pdl
##--------------------------------------------##
- elif tp=='FZ_Mask_Poly':
+ elif tp == "FZ_Mask_Poly":
# print('use FZ fp_poly')
- found_drill=False
- padLayer="F.Mask"
- pts=""
- edgs=[]
+ found_drill = False
+ padLayer = "F.Mask"
+ pts = ""
+ edgs = []
for lines in pad:
- edgs.append(Part.makeLine((lines[1],lines[2],0),(lines[3],lines[4],0)))
- #wd_=float(line[0][4].split('_')[2])
+ edgs.append(Part.makeLine((lines[1], lines[2], 0), (lines[3], lines[4], 0)))
+ # wd_=float(line[0][4].split('_')[2])
# Part.show(Part.makeLine((lines[1],lines[2],0),(lines[3],lines[4],0)))
- face = OSCD2Dg_edgestofaces(edgs,3 , edge_tolerance)
+ face = OSCD2Dg_edgestofaces(edgs, 3, edge_tolerance)
if 0:
- face.check() # reports errors
- face.fix(0,0,0)
- ws=face.Wires
+ face.check() # reports errors
+ face.fix(0, 0, 0)
+ ws = face.Wires
# print('face ws')
- print(face.Wires,len(face.Wires))
+ print(face.Wires, len(face.Wires))
if 1:
Part.show(face)
- f=FreeCAD.ActiveDocument.ActiveObject
+ f = FreeCAD.ActiveDocument.ActiveObject
FreeCAD.ActiveDocument.recompute()
- ws=f.Shape.Wires
- print(ws,len(ws))
+ ws = f.Shape.Wires
+ print(ws, len(ws))
stop
- j=0
+ j = 0
for w in ws:
- j=j+1
+ j = j + 1
# cls=Part.getSortedClusters(w.Edges)
# print(cls)
- clusters = Part.sortEdges(w.Edges) #[0]
+ clusters = Part.sortEdges(w.Edges) # [0]
print(len(clusters))
for cluster in clusters:
- #print(len(cluster))
- pts+=" (fp_poly"+os.linesep+" (pts"+os.linesep
- for i,e in enumerate(cluster): #w.Edges):
- if i < len(cluster)-1:
- pts=pts+" (xy "+"{0:.3f}".format(e.Vertexes[0].X)+" "+"{0:.3f}".format(-1*(e.Vertexes[0].Y))+") (xy "+"{0:.3f}".format(e.Vertexes[1].X)+" "+"{0:.3f}".format(-1*(e.Vertexes[1].Y))+")"+os.linesep
+ # print(len(cluster))
+ pts += " (fp_poly" + os.linesep + " (pts" + os.linesep
+ for i, e in enumerate(cluster): # w.Edges):
+ if i < len(cluster) - 1:
+ pts = (
+ pts
+ + " (xy "
+ + f"{e.Vertexes[0].X:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[0].Y):.3f}"
+ + ") (xy "
+ + f"{e.Vertexes[1].X:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[1].Y):.3f}"
+ + ")"
+ + os.linesep
+ )
else:
- pts=pts+" (xy "+"{0:.3f}".format(e.Vertexes[0].X)+" "+"{0:.3f}".format(-1*(e.Vertexes[0].Y))+")) (layer "+padLayer+") (width 0))"+os.linesep
- print(pts,j)
+ pts = (
+ pts
+ + " (xy "
+ + f"{e.Vertexes[0].X:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[0].Y):.3f}"
+ + ")) (layer "
+ + padLayer
+ + ") (width 0))"
+ + os.linesep
+ )
+ print(pts, j)
return pts
- if 0:
- clusters=Part.getSortedClusters(w.Edges)
+ if 0:
+ clusters = Part.getSortedClusters(w.Edges)
for cluster in clusters:
# print(cluster)
# if len(cluster)>1:
- # print(cluster)
- # for c in cluster:
- # #Part.show(Part.makePolygon(cluster))
- # Part.show(c)
- for i,e in enumerate(cluster): #w.Edges):
- if i < len(cluster)-1:
- pts=pts+" (xy "+"{0:.3f}".format(e.Vertexes[0].X)+" "+"{0:.3f}".format(-1*(e.Vertexes[0].Y))+") (xy "+"{0:.3f}".format(e.Vertexes[1].X)+" "+"{0:.3f}".format(-1*(e.Vertexes[1].Y))+")"+os.linesep
+ # print(cluster)
+ # for c in cluster:
+ # #Part.show(Part.makePolygon(cluster))
+ # Part.show(c)
+ for i, e in enumerate(cluster): # w.Edges):
+ if i < len(cluster) - 1:
+ pts = (
+ pts
+ + " (xy "
+ + f"{e.Vertexes[0].X:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[0].Y):.3f}"
+ + ") (xy "
+ + f"{e.Vertexes[1].X:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[1].Y):.3f}"
+ + ")"
+ + os.linesep
+ )
else:
- pts=pts+" (xy "+"{0:.3f}".format(e.Vertexes[0].X)+" "+"{0:.3f}".format(-1*(e.Vertexes[0].Y))+")) (layer "+padLayer+") (width 0))"+os.linesep
- #print(pts,j)
+ pts = (
+ pts
+ + " (xy "
+ + f"{e.Vertexes[0].X:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[0].Y):.3f}"
+ + ")) (layer "
+ + padLayer
+ + ") (width 0))"
+ + os.linesep
+ )
+ # print(pts,j)
stop
c = Part.makeCompound(edgs)
- s=Part.show(c)
+ s = Part.show(c)
FreeCAD.ActiveDocument.recompute()
- #f = Part.makeFace(s.Shape,'Part::FaceMakerSimple')
- #Part.getSortedClusters(s.Edges)
- ws=s.Shape.Wires
+ # f = Part.makeFace(s.Shape,'Part::FaceMakerSimple')
+ # Part.getSortedClusters(s.Edges)
+ ws = s.Shape.Wires
print(ws)
print(s.Shape.Edges)
- cls=Part.getSortedClusters(s.Shape.Edges)
- print('clsa')
+ cls = Part.getSortedClusters(s.Shape.Edges)
+ print("clsa")
print(cls[0])
- sc=s.Shape.copy()
+ sc = s.Shape.copy()
print(sc.Edges)
- cls=Part.getSortedClusters(sc.Edges)
- print('cls')
+ cls = Part.getSortedClusters(sc.Edges)
+ print("cls")
print(cls[0])
stop
Part.show(Part.makePolygon(cls[0]))
@@ -19605,130 +21279,179 @@ def createFpPad(pad,offset,tp, _drills=None):
for e in edgs:
Part.show(e)
stop
- #f=
- # f= Part.makeFace(sps,'Part::FaceMakerSimple')
+ # f=
+ # f= Part.makeFace(sps,'Part::FaceMakerSimple')
# Part.show(f)
stop
- wr=[]
+ wr = []
if 0:
- pad_ref=" (pad # smd custom (at 0 0 ) (size 0.1 0.1) (layers F.Mask)"+os.linesep
- pad_ref=pad_ref+" (zone_connect 0)"+os.linesep
- pad_ref=pad_ref+" (options (clearance outline) (anchor circle))"+os.linesep
- pad_ref=pad_ref+" (primitives"+os.linesep
- #pad_ref=pad_ref+" (gr_poly"
-
- if 0: #pad[0][0]=='line':
- #sayw(pad)
+ pad_ref = " (pad # smd custom (at 0 0 ) (size 0.1 0.1) (layers F.Mask)" + os.linesep
+ pad_ref = pad_ref + " (zone_connect 0)" + os.linesep
+ pad_ref = pad_ref + " (options (clearance outline) (anchor circle))" + os.linesep
+ pad_ref = pad_ref + " (primitives" + os.linesep
+ # pad_ref=pad_ref+" (gr_poly"
+
+ if 0: # pad[0][0]=='line':
+ # sayw(pad)
if 0:
- pts=" (gr_poly (pts"+os.linesep
+ pts = " (gr_poly (pts" + os.linesep
else:
- pad_ref=" (fp_poly"+os.linesep+" (pts"+os.linesep
- pts=""
- segments_nbr=len(pad)
- i=1
+ pad_ref = " (fp_poly" + os.linesep + " (pts" + os.linesep
+ pts = ""
+ segments_nbr = len(pad)
+ i = 1
for lines in pad:
- if i0:
+ shpName = FreeCAD.ActiveDocument.ActiveObject.Name
+ # say( FreeCAD.ActiveDocument.ActiveObject.Label)
+ shape = FreeCAD.ActiveDocument.ActiveObject.Shape
+ if len(_drills) > 0:
for d in _drills:
- #print d
- point=FreeCAD.Vector(d[0],-1*d[1],0)
- if shape.isInside(point,0,True):
- sayw('pad in poly found! '+str(d[0])+','+str(-1*d[1]))
- found_drill=True
+ # print d
+ point = FreeCAD.Vector(d[0], -1 * d[1], 0)
+ if shape.isInside(point, 0, True):
+ sayw("pad in poly found! " + str(d[0]) + "," + str(-1 * d[1]))
+ found_drill = True
break
- #stop
- #if 1:
+ # stop
+ # if 1:
FreeCAD.ActiveDocument.removeObject(shpName)
- if 1: #if found_drill:
- #print(len(ant.Wires))
- i=1
+ if 1: # if found_drill:
+ # print(len(ant.Wires))
+ i = 1
for w in ant.Wires:
- pattern = '_In+([0-9]*?)_Cu'
+ pattern = "_In+([0-9]*?)_Cu"
result = re.search(pattern, layers[i])
add_maskLayer = True
- if 'B_Cu' in layers[i]:
- padLayer = 'B.Cu'
+ if "B_Cu" in layers[i]:
+ padLayer = "B.Cu"
elif result is not None:
- padLayer = result.group().replace('_Cu','.Cu')[1:]
+ padLayer = result.group().replace("_Cu", ".Cu")[1:]
# print(padLayer)
add_maskLayer = False
else:
- padLayer = 'F.Cu'
- i=i+1
- clusters = Part.sortEdges(w.Edges) #[0]
- #print(len(clusters))
+ padLayer = "F.Cu"
+ i = i + 1
+ clusters = Part.sortEdges(w.Edges) # [0]
+ # print(len(clusters))
for cluster in clusters:
- #print(len(cluster))
- for i,e in enumerate(cluster): #w.Edges):
- if i < len(cluster)-1:
- #if (e.Vertexes[0].X == clusters[i-1].Vertexes[0].X) and (e.Vertexes[0].Y == clusters[i-1].Vertexes[0].Y):
- #pts=pts+" (xy "+str(e.Vertexes[0].X)+" "+str(-1*(e.Vertexes[0].Y))+") (xy "+str(e.Vertexes[1].X)+" "+str(-1*(e.Vertexes[1].Y))+")"+os.linesep
- pts=pts+" (xy "+"{0:.3f}".format(e.Vertexes[0].X)+" "+"{0:.3f}".format(-1*(e.Vertexes[0].Y))+") (xy "+"{0:.3f}".format(e.Vertexes[1].X)+" "+"{0:.3f}".format(-1*(e.Vertexes[1].Y))+")"+os.linesep
- #float("{0:.3f}".format(value))
- #else:
- # pts=pts+" (xy "+str(e.Vertexes[1].X)+" "+str(-1*(e.Vertexes[1].Y))+") (xy "+str(e.Vertexes[0].X)+" "+str(-1*(e.Vertexes[0].Y))+")"+os.linesep
+ # print(len(cluster))
+ for i, e in enumerate(cluster): # w.Edges):
+ if i < len(cluster) - 1:
+ # if (e.Vertexes[0].X == clusters[i-1].Vertexes[0].X) and (e.Vertexes[0].Y == clusters[i-1].Vertexes[0].Y):
+ # pts=pts+" (xy "+str(e.Vertexes[0].X)+" "+str(-1*(e.Vertexes[0].Y))+") (xy "+str(e.Vertexes[1].X)+" "+str(-1*(e.Vertexes[1].Y))+")"+os.linesep
+ pts = (
+ pts
+ + " (xy "
+ + f"{e.Vertexes[0].X:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[0].Y):.3f}"
+ + ") (xy "
+ + f"{e.Vertexes[1].X:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[1].Y):.3f}"
+ + ")"
+ + os.linesep
+ )
+ # float("{0:.3f}".format(value))
+ # else:
+ # pts=pts+" (xy "+str(e.Vertexes[1].X)+" "+str(-1*(e.Vertexes[1].Y))+") (xy "+str(e.Vertexes[0].X)+" "+str(-1*(e.Vertexes[0].Y))+")"+os.linesep
else:
- #"{0:.3f}".format(
- pts=pts+" (xy "+"{0:.3f}".format(e.Vertexes[0].X)+" "+"{0:.3f}".format(-1*(e.Vertexes[0].Y))+")) (layer "+padLayer+") (width 0))"+os.linesep
- #pts=pts+" (xy "+str(e.Vertexes[0].X)+" "+str(-1*(e.Vertexes[0].Y))+")) (layer "+padLayer+") (width 0))"+os.linesep
- #i=1
- #for lines in pad:
+ # "{0:.3f}".format(
+ pts = (
+ pts
+ + " (xy "
+ + f"{e.Vertexes[0].X:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[0].Y):.3f}"
+ + ")) (layer "
+ + padLayer
+ + ") (width 0))"
+ + os.linesep
+ )
+ # pts=pts+" (xy "+str(e.Vertexes[0].X)+" "+str(-1*(e.Vertexes[0].Y))+")) (layer "+padLayer+") (width 0))"+os.linesep
+ # i=1
+ # for lines in pad:
# if i1:
@@ -19770,185 +21493,270 @@ def createFpPad(pad,offset,tp, _drills=None):
# pts=pts+" (xy "+str(lines[1])+" "+str(-1*lines[2])+")) (layer F.Cu) (width 0))"+os.linesep
# #i=i+1
if add_maskLayer:
- pts = pts + pts.replace('.Cu','.Mask')
- #pad_ref=" (pad "+str(pad_nbr)+" smd custom (at "+str(d[0])+" "+str(d[1])+" ) (size "+str(d[2])+" "+str(d[2])+") (layers F.Cu F.Paste F.Mask)"+os.linesep
+ pts = pts + pts.replace(".Cu", ".Mask")
+ # pad_ref=" (pad "+str(pad_nbr)+" smd custom (at "+str(d[0])+" "+str(d[1])+" ) (size "+str(d[2])+" "+str(d[2])+") (layers F.Cu F.Paste F.Mask)"+os.linesep
if found_drill:
if add_maskLayer:
- pad_ref=" (pad "+padNbr+" smd circle (at "+"{0:.3f}".format(d[0])+" "+"{0:.3f}".format(d[1])+" ) (size "+"{0:.3f}".format(d[2])+" "+"{0:.3f}".format(d[2])+") (layers "+padLayer+" "+padLayer.rstrip('Cu')+"Mask))"+os.linesep
+ pad_ref = (
+ " (pad "
+ + padNbr
+ + " smd circle (at "
+ + f"{d[0]:.3f}"
+ + " "
+ + f"{d[1]:.3f}"
+ + " ) (size "
+ + f"{d[2]:.3f}"
+ + " "
+ + f"{d[2]:.3f}"
+ + ") (layers "
+ + padLayer
+ + " "
+ + padLayer.rstrip("Cu")
+ + "Mask))"
+ + os.linesep
+ )
else:
- pad_ref=" (pad "+padNbr+" smd circle (at "+"{0:.3f}".format(d[0])+" "+"{0:.3f}".format(d[1])+" ) (size "+"{0:.3f}".format(d[2])+" "+"{0:.3f}".format(d[2])+") (layers "+padLayer+"))"+os.linesep
- #if 0: #'B_Cu' in tp:
+ pad_ref = (
+ " (pad "
+ + padNbr
+ + " smd circle (at "
+ + f"{d[0]:.3f}"
+ + " "
+ + f"{d[1]:.3f}"
+ + " ) (size "
+ + f"{d[2]:.3f}"
+ + " "
+ + f"{d[2]:.3f}"
+ + ") (layers "
+ + padLayer
+ + "))"
+ + os.linesep
+ )
+ # if 0: #'B_Cu' in tp:
# #pad_ref=" (pad # smd custom (at "+str("{0:.3f}".format(d[0]))+" "+str("{0:.3f}".format(d[1]))+" ) (size "+str("{0:.3f}".format(d[2]))+" "+str("{0:.3f}".format(d[2]))+") (layers B.Cu B.Paste B.Mask)"+os.linesep
# pad_ref=" (pad # smd circle (at "+str("{0:.3f}".format(d[0]))+" "+str("{0:.3f}".format(d[1]))+" ) (size "+str("{0:.3f}".format(d[2]))+" "+str("{0:.3f}".format(d[2]))+") (layers B.Cu B.Mask))"+os.linesep
- #else:
+ # else:
# #pad_ref=" (pad # smd custom (at "+str("{0:.3f}".format(d[0]))+" "+str("{0:.3f}".format(d[1]))+" ) (size "+str("{0:.3f}".format(d[2]))+" "+str("{0:.3f}".format(d[2]))+") (layers F.Cu F.Paste F.Mask)"+os.linesep
# pad_ref=" (pad # smd circle (at "+str("{0:.3f}".format(d[0]))+" "+str("{0:.3f}".format(d[1]))+" ) (size "+str("{0:.3f}".format(d[2]))+" "+str("{0:.3f}".format(d[2]))+") (layers F.Cu F.Mask))"+os.linesep
else:
- pad_ref=""
+ pad_ref = ""
# #pad_ref=" (pad # smd custom (at "+str("{0:.3f}".format(d[0]))+" "+str("{0:.3f}".format(d[1]))+" ) (size "+str("{0:.3f}".format(d[2]))+" "+str("{0:.3f}".format(d[2]))+") (layers F.Cu F.Paste F.Mask)"+os.linesep
# pad_ref=pad_ref+" (zone_connect 0)"+os.linesep
# pad_ref=pad_ref+" (options (clearance outline) (anchor circle))"+os.linesep
# pad_ref=pad_ref+" (primitives"+os.linesep
# #pad_ref=pad_ref+" (gr_poly (pts"+os.linesep
- #if pad_ref!="":
+ # if pad_ref!="":
# pad_ref=pad_ref+pts
# pad_ref=pad_ref+" ))"+os.linesep
- #else:
+ # else:
# pad_ref=pad_ref+pts+os.linesep
- pad_ref=pad_ref+pts+os.linesep
- #sayerr(pad_ref)
- pad_nbr=pad_nbr+1
- found_drill=False
+ pad_ref = pad_ref + pts + os.linesep
+ # sayerr(pad_ref)
+ pad_nbr = pad_nbr + 1
+ found_drill = False
else:
sayw("missing reference pad for polyline pad")
- #stop
+ # stop
return pad_ref
-###
- #elif tp=='Poly':
- elif 'Poly' in tp: #NB after NetTie_Poly
- found_drill=False
- wr=[]
- if pad[0][0]=='line':
- #sayw(pad)
- pts=" (gr_poly (pts"+os.linesep
- segments_nbr=len(pad)
- i=1
+ ###
+ # elif tp=='Poly':
+ elif "Poly" in tp: # NB after NetTie_Poly
+ found_drill = False
+ wr = []
+ if pad[0][0] == "line":
+ # sayw(pad)
+ pts = " (gr_poly (pts" + os.linesep
+ segments_nbr = len(pad)
+ i = 1
layers = []
- pnts=[]
+ pnts = []
for lines in pad:
- #if i0:
+ # print("len(_drills)",len(_drills))
+ if len(_drills) > 0:
for d in _drills:
- #print (d)
- point=FreeCAD.Vector(d[0],-1*d[1],0)
- #print(point)
- if shape.isInside(point,0,True):
- sayw('pad in poly found! '+str(d[0])+','+str(-1*d[1]))
- found_drill=True
+ # print (d)
+ point = FreeCAD.Vector(d[0], -1 * d[1], 0)
+ # print(point)
+ if shape.isInside(point, 0, True):
+ sayw("pad in poly found! " + str(d[0]) + "," + str(-1 * d[1]))
+ found_drill = True
break
# FreeCAD.ActiveDocument.removeObject(shpName)
- #stop
- #if 1:
+ # stop
+ # if 1:
if found_drill:
- i=1
+ i = 1
for w in ant.Shape.Wires:
- pattern = '_In+([0-9]*?)_Cu'
+ pattern = "_In+([0-9]*?)_Cu"
result = re.search(pattern, layers[i])
- clusters = Part.sortEdges(w.Edges) #[0]
+ clusters = Part.sortEdges(w.Edges) # [0]
internalLayer = False
print(layers[i])
- if 'B_Cu' in layers[i]:
- padLayer = 'B.Cu'
+ if "B_Cu" in layers[i]:
+ padLayer = "B.Cu"
elif result is not None:
- padLayer = result.group().replace('_Cu','.Cu')[1:]
+ padLayer = result.group().replace("_Cu", ".Cu")[1:]
internalLayer = True
else:
- padLayer = 'F.Cu'
- i=i+1
- #print(len(clusters))
+ padLayer = "F.Cu"
+ i = i + 1
+ # print(len(clusters))
for cluster in clusters:
- #print(len(cluster))
- for i,e in enumerate(cluster): #w.Edges):
- if i < len(cluster)-1:
- #if (e.Vertexes[0].X == clusters[i-1].Vertexes[0].X) and (e.Vertexes[0].Y == clusters[i-1].Vertexes[0].Y):
- pts=pts+" (xy "+"{0:.3f}".format(e.Vertexes[0].X-d[0])+" "+"{0:.3f}".format(-1*(e.Vertexes[0].Y)-d[1])+") (xy "+"{0:.3f}".format(e.Vertexes[1].X-d[0])+" "+"{0:.3f}".format(-1*(e.Vertexes[1].Y)-d[1])+")"+os.linesep
- #else:
- # pts=pts+" (xy "+str(e.Vertexes[1].X)+" "+str(-1*(e.Vertexes[1].Y))+") (xy "+str(e.Vertexes[0].X)+" "+str(-1*(e.Vertexes[0].Y))+")"+os.linesep
+ # print(len(cluster))
+ for i, e in enumerate(cluster): # w.Edges):
+ if i < len(cluster) - 1:
+ # if (e.Vertexes[0].X == clusters[i-1].Vertexes[0].X) and (e.Vertexes[0].Y == clusters[i-1].Vertexes[0].Y):
+ pts = (
+ pts
+ + " (xy "
+ + f"{e.Vertexes[0].X - d[0]:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[0].Y) - d[1]:.3f}"
+ + ") (xy "
+ + f"{e.Vertexes[1].X - d[0]:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[1].Y) - d[1]:.3f}"
+ + ")"
+ + os.linesep
+ )
+ # else:
+ # pts=pts+" (xy "+str(e.Vertexes[1].X)+" "+str(-1*(e.Vertexes[1].Y))+") (xy "+str(e.Vertexes[0].X)+" "+str(-1*(e.Vertexes[0].Y))+")"+os.linesep
else:
- pts=pts+" (xy "+"{0:.3f}".format(e.Vertexes[0].X-d[0])+" "+"{0:.3f}".format(-1*(e.Vertexes[0].Y)-d[1])+")) (layer "+padLayer+") (width 0))"+os.linesep
- #pts = pts + pts.replace('F.Cu','F.Mask')
- #pad_ref=" (pad "+str(pad_nbr)+" smd custom (at "+str(d[0])+" "+str(d[1])+" ) (size "+str(d[2])+" "+str(d[2])+") (layers F.Cu F.Paste F.Mask)"+os.linesep
- if found_drill: #ref pad found
+ pts = (
+ pts
+ + " (xy "
+ + f"{e.Vertexes[0].X - d[0]:.3f}"
+ + " "
+ + f"{-1 * (e.Vertexes[0].Y) - d[1]:.3f}"
+ + ")) (layer "
+ + padLayer
+ + ") (width 0))"
+ + os.linesep
+ )
+ # pts = pts + pts.replace('F.Cu','F.Mask')
+ # pad_ref=" (pad "+str(pad_nbr)+" smd custom (at "+str(d[0])+" "+str(d[1])+" ) (size "+str(d[2])+" "+str(d[2])+") (layers F.Cu F.Paste F.Mask)"+os.linesep
+ if found_drill: # ref pad found
if internalLayer:
- pad_ref=" (pad "+padNbr+" smd custom (at "+"{0:.3f}".format(d[0])+" "+"{0:.3f}".format(d[1])+" ) (size "+"{0:.3f}".format(d[2])+" "+"{0:.3f}".format(d[2])+") (layers "+padLayer+")"+os.linesep
+ pad_ref = (
+ " (pad "
+ + padNbr
+ + " smd custom (at "
+ + f"{d[0]:.3f}"
+ + " "
+ + f"{d[1]:.3f}"
+ + " ) (size "
+ + f"{d[2]:.3f}"
+ + " "
+ + f"{d[2]:.3f}"
+ + ") (layers "
+ + padLayer
+ + ")"
+ + os.linesep
+ )
else:
- pad_ref=" (pad "+padNbr+" smd custom (at "+"{0:.3f}".format(d[0])+" "+"{0:.3f}".format(d[1])+" ) (size "+"{0:.3f}".format(d[2])+" "+"{0:.3f}".format(d[2])+") (layers "+padLayer+" "+padLayer.rstrip('Cu')+"Mask)"+os.linesep
-
- #if 'B_Cu' in lyr:
+ pad_ref = (
+ " (pad "
+ + padNbr
+ + " smd custom (at "
+ + f"{d[0]:.3f}"
+ + " "
+ + f"{d[1]:.3f}"
+ + " ) (size "
+ + f"{d[2]:.3f}"
+ + " "
+ + f"{d[2]:.3f}"
+ + ") (layers "
+ + padLayer
+ + " "
+ + padLayer.rstrip("Cu")
+ + "Mask)"
+ + os.linesep
+ )
+
+ # if 'B_Cu' in lyr:
# pad_ref=" (pad # smd custom (at "+str("{0:.3f}".format(d[0]))+" "+str("{0:.3f}".format(d[1]))+" ) (size "+str("{0:.3f}".format(d[2]))+" "+str("{0:.3f}".format(d[2]))+") (layers B.Cu B.Paste B.Mask)"+os.linesep
# #pad_ref=" (pad # smd custom (at "+str("{0:.3f}".format(d[0]))+" "+str("{0:.3f}".format(d[1]))+" ) (size "+str("{0:.3f}".format(d[2]))+" "+str("{0:.3f}".format(d[2]))+") (layers B.Cu B.Mask)"+os.linesep
- #else:
+ # else:
# #pad_ref=" (pad # smd custom (at "+str("{0:.3f}".format(d[0]))+" "+str("{0:.3f}".format(d[1]))+" ) (size "+str("{0:.3f}".format(d[2]))+" "+str("{0:.3f}".format(d[2]))+") (layers F.Cu F.Paste F.Mask)"+os.linesep
# pad_ref=" (pad # smd custom (at "+str("{0:.3f}".format(d[0]))+" "+str("{0:.3f}".format(d[1]))+" ) (size "+str("{0:.3f}".format(d[2]))+" "+str("{0:.3f}".format(d[2]))+") (layers F.Cu F.Mask)"+os.linesep
- #else:
+ # else:
# pad_ref=""
# pad_ref=pad_ref+pts+os.linesep
# #pad_ref=" (pad # smd custom (at "+str("{0:.3f}".format(d[0]))+" "+str("{0:.3f}".format(d[1]))+" ) (size "+str("{0:.3f}".format(d[2]))+" "+str("{0:.3f}".format(d[2]))+") (layers F.Cu F.Paste F.Mask)"+os.linesep
- pad_ref=pad_ref+" (zone_connect 0)"+os.linesep
- pad_ref=pad_ref+" (options (clearance outline) (anchor circle))"+os.linesep
- pad_ref=pad_ref+" (primitives"+os.linesep
+ pad_ref = pad_ref + " (zone_connect 0)" + os.linesep
+ pad_ref = pad_ref + " (options (clearance outline) (anchor circle))" + os.linesep
+ pad_ref = pad_ref + " (primitives" + os.linesep
# #pad_ref=pad_ref+" (gr_poly (pts"+os.linesep
- #if pad_ref!="":
- pad_ref=pad_ref+pts
- pad_ref=pad_ref+" ))"+os.linesep
- #pad_ref=pad_ref+pts+" ))"+os.linesep
- #sayerr(pad_ref)
- pad_nbr=pad_nbr+1
- found_drill=False
+ # if pad_ref!="":
+ pad_ref = pad_ref + pts
+ pad_ref = pad_ref + " ))" + os.linesep
+ # pad_ref=pad_ref+pts+" ))"+os.linesep
+ # sayerr(pad_ref)
+ pad_nbr = pad_nbr + 1
+ found_drill = False
else:
sayw("missing reference pad for polyline pad")
stop
FreeCAD.ActiveDocument.removeObject(shpName)
return pad_ref
-
# if found_drill:
# i=1
# for lines in pad:
@@ -19975,18 +21783,18 @@ def createFpPad(pad,offset,tp, _drills=None):
# else:
# sayerr("missing reference pad for polyline pad")
# stop
- #Part.show(face)
- #(pad 1 smd custom (at 1 2) (size 0.2 0.2) (layers F.Cu F.Paste F.Mask)
- #(zone_connect 0)
- #(options (clearance outline) (anchor circle))
- #(primitives
- #(gr_poly (pts
- # (xy -3.0 1.0) (xy -4.0 1.0) (xy -3.0 -2.0) (xy -0.5 -2.0) (xy 1.0 -4.0)
- # (xy 4.0 -2.0) (xy 5.0 2.0) (xy 1.0 3.0)) (width 0))
- #))
- #sayerr(pts)
-
- #say(_drills)
+ # Part.show(face)
+ # (pad 1 smd custom (at 1 2) (size 0.2 0.2) (layers F.Cu F.Paste F.Mask)
+ # (zone_connect 0)
+ # (options (clearance outline) (anchor circle))
+ # (primitives
+ # (gr_poly (pts
+ # (xy -3.0 1.0) (xy -4.0 1.0) (xy -3.0 -2.0) (xy -0.5 -2.0) (xy 1.0 -4.0)
+ # (xy 4.0 -2.0) (xy 5.0 2.0) (xy 1.0 3.0)) (width 0))
+ # ))
+ # sayerr(pts)
+
+ # say(_drills)
# sayerr('poly rect pad nbr.'+str(pad_nbr))
# p1=(pad[0][1],pad[0][2]);p2=(pad[0][3]+pad[0][4])
# sayerr('segment='+p1+','+p2
@@ -20027,109 +21835,145 @@ def createFpPad(pad,offset,tp, _drills=None):
# pad_nbr=pad_nbr+1
# say(pad);sayw(pdl)
# return pdl
- #return pad_ref
-##
- elif tp=='Pads_Geom':
- found_drill=False
- wr=[]
- if len(_drills)>0:
+ # return pad_ref
+ ##
+ elif tp == "Pads_Geom":
+ found_drill = False
+ wr = []
+ if len(_drills) > 0:
for d in _drills:
- #print d
- sayw('drill found! '+str(d[0])+','+str(-1*d[1]))
- found_drill=True
+ # print d
+ sayw("drill found! " + str(d[0]) + "," + str(-1 * d[1]))
+ found_drill = True
break
- if pad[0][0]=='line':
- sayw('line is not supported')
- elif pad[0][0]=='circle':
- print (pad)
- wd_=float(pad[0][4].split('_')[2])
- pts=" (gr_circle (center "+"{0:.3f}".format(pad[0][2]-d[0])+" "+"{0:.3f}".format(-1*pad[0][3]-d[1])+") (end "+"{0:.3f}".format(pad[0][2]-d[0]+pad[0][1])+" "+"{0:.3f}".format(-1*pad[0][3]-d[1])+") (width "+"{0:.3f}".format(wd_)+"))"+os.linesep
+ if pad[0][0] == "line":
+ sayw("line is not supported")
+ elif pad[0][0] == "circle":
+ print(pad)
+ wd_ = float(pad[0][4].split("_")[2])
+ pts = (
+ " (gr_circle (center "
+ + f"{pad[0][2] - d[0]:.3f}"
+ + " "
+ + f"{-1 * pad[0][3] - d[1]:.3f}"
+ + ") (end "
+ + f"{pad[0][2] - d[0] + pad[0][1]:.3f}"
+ + " "
+ + f"{-1 * pad[0][3] - d[1]:.3f}"
+ + ") (width "
+ + f"{wd_:.3f}"
+ + "))"
+ + os.linesep
+ )
say(pts)
if found_drill:
- #pad_ref=" (pad "+str(pad_nbr)+" smd custom (at "+str(d[0])+" "+str(d[1])+" ) (size "+str(d[2])+" "+str(d[2])+") (layers F.Cu F.Paste F.Mask)"+os.linesep
- if 0: #'B_Cu' in tp:
- pad_ref=" (pad # smd custom (at "+str("{0:.3f}".format(d[0]))+" "+str("{0:.3f}".format(d[1]))+" ) (size "+str(d[2])+" "+str(d[2])+") (layers B.Cu B.Paste B.Mask)"+os.linesep
+ # pad_ref=" (pad "+str(pad_nbr)+" smd custom (at "+str(d[0])+" "+str(d[1])+" ) (size "+str(d[2])+" "+str(d[2])+") (layers F.Cu F.Paste F.Mask)"+os.linesep
+ if 0: #'B_Cu' in tp:
+ pad_ref = (
+ " (pad # smd custom (at "
+ + str(f"{d[0]:.3f}")
+ + " "
+ + str(f"{d[1]:.3f}")
+ + " ) (size "
+ + str(d[2])
+ + " "
+ + str(d[2])
+ + ") (layers B.Cu B.Paste B.Mask)"
+ + os.linesep
+ )
else:
- pad_ref=" (pad # smd custom (at "+str("{0:.3f}".format(d[0]))+" "+str("{0:.3f}".format(d[1]))+" ) (size "+str(d[2])+" "+str(d[2])+") (layers F.Cu F.Paste F.Mask)"+os.linesep
- pad_ref=pad_ref+" (zone_connect 0)"+os.linesep
- pad_ref=pad_ref+" (options (clearance outline) (anchor circle))"+os.linesep
- pad_ref=pad_ref+" (primitives"+os.linesep
- #pad_ref=pad_ref+" (gr_poly (pts"+os.linesep
- pad_ref=pad_ref+pts
- pad_ref=pad_ref+" ))"+os.linesep
- #sayerr(pad_ref)
- pad_nbr=pad_nbr+1
- found_drill=False
+ pad_ref = (
+ " (pad # smd custom (at "
+ + str(f"{d[0]:.3f}")
+ + " "
+ + str(f"{d[1]:.3f}")
+ + " ) (size "
+ + str(d[2])
+ + " "
+ + str(d[2])
+ + ") (layers F.Cu F.Paste F.Mask)"
+ + os.linesep
+ )
+ pad_ref = pad_ref + " (zone_connect 0)" + os.linesep
+ pad_ref = pad_ref + " (options (clearance outline) (anchor circle))" + os.linesep
+ pad_ref = pad_ref + " (primitives" + os.linesep
+ # pad_ref=pad_ref+" (gr_poly (pts"+os.linesep
+ pad_ref = pad_ref + pts
+ pad_ref = pad_ref + " ))" + os.linesep
+ # sayerr(pad_ref)
+ pad_nbr = pad_nbr + 1
+ found_drill = False
else:
sayerr("missing reference pad for polyline pad")
stop
return pad_ref
else:
- return u''
- pass
+ return ""
+ return None
###
+
def getBoardOutline():
global edge_tolerance, maxRadius, maxSegments
global dvm, dqd, precision
-
- use_discretize = False # discretize or toBiArc method for Ellipses and parabola and Hyperbola
-
+
+ use_discretize = False # discretize or toBiArc method for Ellipses and parabola and Hyperbola
+
if not FreeCAD.activeDocument():
return False
- #
- doc = FreeCAD.activeDocument()
+ FreeCAD.activeDocument()
outline = []
- #to_discretize=[[]] * 2 #[[][]]
- to_discretize=[]
- construction_geom=[]
- not_supported = ''
-
+ # to_discretize=[[]] * 2 #[[][]]
+ to_discretize = []
+ construction_geom = []
+ not_supported = ""
+
sel = FreeCADGui.Selection.getSelection()
- if len (sel) >0:
- #sayw(doc.Name)
+ if len(sel) > 0:
+ # sayw(doc.Name)
for j in sel:
- #for j in doc.Objects:
+ # for j in doc.Objects:
sayerr(j.Name)
- #sayw(j.Geometry)
-
- #if hasattr(j, "Proxy") and hasattr(j.Proxy, "Type") and j.Proxy.Type == "PCBboard":
+ # sayw(j.Geometry)
+
+ # if hasattr(j, "Proxy") and hasattr(j.Proxy, "Type") and j.Proxy.Type == "PCBboard":
##if hasattr(j, "Geometry"):
if "Sketch" in j.TypeId:
try:
- #print j.Geometry
+ # print j.Geometry
for k in range(len(j.Geometry)):
- #print(type(j.Geometry[k]).__name__)
- bezier_list = []
- bezier_list_tmp = []
- if 0: #hasattr(j,'GeometryFacadeList'):
+ # print(type(j.Geometry[k]).__name__)
+ bezier_list = []
+ if 0: # hasattr(j,'GeometryFacadeList'):
Gm = j.GeometryFacadeList
else:
Gm = j.Geometry
- #if hasattr(Gm[k],'Construction'):
+ # if hasattr(Gm[k],'Construction'):
if isConstruction(Gm[k]):
- #if Gm[k].Construction:
+ # if Gm[k].Construction:
construction_geom.append(k)
- sayw('construction skipped')
+ sayw("construction skipped")
continue
- if 'Point' in type(Gm[k]).__name__: #skipping points
- sayw('point skipped')
- #sayerr('point')
+ if "Point" in type(Gm[k]).__name__: # skipping points
+ sayw("point skipped")
+ # sayerr('point')
continue
- #if type(j.Geometry[k]).__name__ == 'LineSegment':
- if 'LineSegment' in type(Gm[k]).__name__:
- #if 'Line' in type(j.Geometry[k]).__name__:
- sk_ge=Gm[k].toShape() #needed to fix some issue on sketch geometry building
- outline.append([
- 'line',
- sk_ge.Edges[0].Vertexes[0].Point.x,
- sk_ge.Edges[0].Vertexes[0].Point.y,
- sk_ge.Edges[0].Vertexes[1].Point.x,
- sk_ge.Edges[0].Vertexes[1].Point.y,
- j.Label
- ])
+ # if type(j.Geometry[k]).__name__ == 'LineSegment':
+ if "LineSegment" in type(Gm[k]).__name__:
+ # if 'Line' in type(j.Geometry[k]).__name__:
+ sk_ge = Gm[k].toShape() # needed to fix some issue on sketch geometry building
+ outline.append(
+ [
+ "line",
+ sk_ge.Edges[0].Vertexes[0].Point.x,
+ sk_ge.Edges[0].Vertexes[0].Point.y,
+ sk_ge.Edges[0].Vertexes[1].Point.x,
+ sk_ge.Edges[0].Vertexes[1].Point.y,
+ j.Label,
+ ],
+ )
# outline.append([
# 'line',
# j.Geometry[k].StartPoint.x,
@@ -20137,60 +21981,64 @@ def getBoardOutline():
# j.Geometry[k].EndPoint.x,
# j.Geometry[k].EndPoint.y
# ])
- #elif type(j.Geometry[k]).__name__ == 'Circle':
- elif 'Circle' in type(Gm[k]).__name__ and not 'ArcOfCircle' in type(Gm[k]).__name__:
- sk_ge=Gm[k].toShape() #needed to fix some issue on sketch geometry building
- outline.append([
- 'circle',
- sk_ge.Edges[0].Curve.Radius,
- sk_ge.Edges[0].Curve.Center.x,
- sk_ge.Edges[0].Curve.Center.y,
- j.Label
- ])
+ # elif type(j.Geometry[k]).__name__ == 'Circle':
+ elif "Circle" in type(Gm[k]).__name__ and "ArcOfCircle" not in type(Gm[k]).__name__:
+ sk_ge = Gm[k].toShape() # needed to fix some issue on sketch geometry building
+ outline.append(
+ [
+ "circle",
+ sk_ge.Edges[0].Curve.Radius,
+ sk_ge.Edges[0].Curve.Center.x,
+ sk_ge.Edges[0].Curve.Center.y,
+ j.Label,
+ ],
+ )
# outline.append([
# 'circle',
# j.Geometry[k].Radius,
- # j.Geometry[k].Center.x,
+ # j.Geometry[k].Center.x,
# j.Geometry[k].Center.y
# ])
- #elif type(j.Geometry[k]).__name__ == 'ArcOfCircle':
- #elif isinstance(j.Geometry[k].Curve,Part.Circle)
- elif 'ArcOfCircle' in type(Gm[k]).__name__:
- #if isinstance(j.Shape.Edges[k].Curve,Part.Circle):
- #sayw(type(j.Geometry[k]))
- #sayerr(j.Shape.Edges[k].Curve)
- #print('arc')
- sk_ge=Gm[k].toShape() #needed to fix some issue on sketch geometry building
- outline.append([
- 'arc',
- Gm[k].Radius,
- sk_ge.Edges[0].Curve.Center.x,
- sk_ge.Edges[0].Curve.Center.y,
- Gm[k].FirstParameter,
- Gm[k].LastParameter,
- Gm[k].Axis[0],
- Gm[k].Axis[1],
- Gm[k].Axis[2],
- Gm[k],
- sk_ge.Edges[0].Vertexes[0].Point,
- sk_ge.Edges[0].Vertexes[1].Point,
- sk_ge.Edges[0].Orientation,
- j.Label
- ])
- ##j.Geometry[k].Center.x,
- ##j.Geometry[k].Center.y,
-
+ # elif type(j.Geometry[k]).__name__ == 'ArcOfCircle':
+ # elif isinstance(j.Geometry[k].Curve,Part.Circle)
+ elif "ArcOfCircle" in type(Gm[k]).__name__:
+ # if isinstance(j.Shape.Edges[k].Curve,Part.Circle):
+ # sayw(type(j.Geometry[k]))
+ # sayerr(j.Shape.Edges[k].Curve)
+ # print('arc')
+ sk_ge = Gm[k].toShape() # needed to fix some issue on sketch geometry building
+ outline.append(
+ [
+ "arc",
+ Gm[k].Radius,
+ sk_ge.Edges[0].Curve.Center.x,
+ sk_ge.Edges[0].Curve.Center.y,
+ Gm[k].FirstParameter,
+ Gm[k].LastParameter,
+ Gm[k].Axis[0],
+ Gm[k].Axis[1],
+ Gm[k].Axis[2],
+ Gm[k],
+ sk_ge.Edges[0].Vertexes[0].Point,
+ sk_ge.Edges[0].Vertexes[1].Point,
+ sk_ge.Edges[0].Orientation,
+ j.Label,
+ ],
+ )
+ ##j.Geometry[k].Center.x,
+ ##j.Geometry[k].Center.y,
+
# i=j.Geometry[k]
# sayerr('Xaxis1a')
# if 0: #i.XAxis.x < 0: ## da cambiare this is not available on FC0.16
# sayerr('Xaxis1b')
# outline.append([
# 'arc',
- # i.Radius,
- # i.Center.x,
- # i.Center.y,
+ # i.Radius,
+ # i.Center.x,
+ # i.Center.y,
# i.LastParameter+pi,
- # i.FirstParameter+pi,
+ # i.FirstParameter+pi,
# -i.Axis[0],
# i.Axis[1],
# i.Axis[2],
@@ -20199,102 +22047,114 @@ def getBoardOutline():
# else:
# outline.append([
# 'arc',
- # i.Radius,
- # i.Center.x,
- # i.Center.y,
+ # i.Radius,
+ # i.Center.x,
+ # i.Center.y,
# i.LastParameter,
- # i.FirstParameter+pi,
+ # i.FirstParameter+pi,
# i.Axis[0],
# i.Axis[1],
# i.Axis[2],
# i
# ])
- elif (accept_spline) and ('BSplineCurve' in type(Gm[k]).__name__):
+ elif (accept_spline) and ("BSplineCurve" in type(Gm[k]).__name__):
bs = Gm[k]
# Set degree
- #maxDegree = 3 #kicad max degree of splines
+ # maxDegree = 3 #kicad max degree of splines
if bs.Degree < maxDegree:
bs.increaseDegree(maxDegree)
elif bs.Degree > maxDegree:
# degree too high. We need to approximate the curve
- bs = bs.approximateBSpline(edge_tolerance,maxSegments,maxDegree) # (tolerance, maxSegments, maxDegree)
+ bs = bs.approximateBSpline(
+ edge_tolerance,
+ maxSegments,
+ maxDegree,
+ ) # (tolerance, maxSegments, maxDegree)
# Generate to a list of bezier curves
- bezier_list.extend(bs.toBezier()) # Generate to a list of bezier curves, these are of 4 poles
+ bezier_list.extend(
+ bs.toBezier(),
+ ) # Generate to a list of bezier curves, these are of 4 poles
for bc in bezier_list:
- print("%s (degree : %d / nb poles : %d)"%(bc, bc.Degree, bc.NbPoles))
+ print(f"{bc} (degree : {bc.Degree} / nb poles : {bc.NbPoles})")
# poles = bc.getPoles()
# spline=Part.BSplineCurve()
# spline.buildFromPoles(poles, False, 3)
- #kicadGeo.append(spline)
- #print(poles)
- outline.append([
- 'spline',
- bc.getPole(1).x,
- bc.getPole(1).y,
- bc.getPole(2).x,
- bc.getPole(2).y,
- bc.getPole(3).x,
- bc.getPole(3).y,
- bc.getPole(4).x,
- bc.getPole(4).y,
- j.Label
- ])
- #print(outline)
+ # kicadGeo.append(spline)
+ # print(poles)
+ outline.append(
+ [
+ "spline",
+ bc.getPole(1).x,
+ bc.getPole(1).y,
+ bc.getPole(2).x,
+ bc.getPole(2).y,
+ bc.getPole(3).x,
+ bc.getPole(3).y,
+ bc.getPole(4).x,
+ bc.getPole(4).y,
+ j.Label,
+ ],
+ )
+ # print(outline)
# elif (use_discretize) and (accept_spline) and ('Parabola' in type(j.Geometry[k]).__name__ or 'Hyperbola' in type(j.Geometry[k]).__name__\
- # or 'Ellipse' in type(j.Geometry[k]).__name__):
- elif (accept_spline) and ('Parabol' in type(Gm[k]).__name__ or 'Hyperbol' in type(Gm[k]).__name__):
- ## discretizing
- # or 'Ellipse' in type(j.Geometry[k]).__name__ ## Ellipses are not well approximated by Splines
+ # or 'Ellipse' in type(j.Geometry[k]).__name__):
+ elif (accept_spline) and (
+ "Parabol" in type(Gm[k]).__name__ or "Hyperbol" in type(Gm[k]).__name__
+ ):
+ ## discretizing
+ # or 'Ellipse' in type(j.Geometry[k]).__name__ ## Ellipses are not well approximated by Splines
gd = Gm[k]
gds = gd.toShape()
pl = gds.discretize(QuasiDeflection=dqd)
- #pl = gds.discretize(QuasiDeflection=1.0)
+ # pl = gds.discretize(QuasiDeflection=1.0)
w = Part.makePolygon(pl)
wv = w.Vertexes
- for i in range(0,len(wv), 1):
- #for v in wv:
- if i < len(wv)-1:
+ for i in range(0, len(wv), 1):
+ # for v in wv:
+ if i < len(wv) - 1:
v1x = wv[i].Point.x
v1y = wv[i].Point.y
- v2x = wv[i+1].Point.x
- v2y = wv[i+1].Point.y
- elif 'Arc' not in str(gd):
+ v2x = wv[i + 1].Point.x
+ v2y = wv[i + 1].Point.y
+ elif "Arc" not in str(gd):
v1x = wv[i].Point.x
v1y = wv[i].Point.y
v2x = wv[0].Point.x
v2y = wv[0].Point.y
- #print('last point',v1x,v1y,v2x,v2y)
- #i+=2
- outline.append([
- 'line',
- v1x,
- v1y,
- v2x,
- v2y,
- j.Label,
- ])
- #print(v1x,v1y,v2x,v2y,i)
+ # print('last point',v1x,v1y,v2x,v2y)
+ # i+=2
+ outline.append(
+ [
+ "line",
+ v1x,
+ v1y,
+ v2x,
+ v2y,
+ j.Label,
+ ],
+ )
+ # print(v1x,v1y,v2x,v2y,i)
# elif (not use_discretize) and (accept_spline) and ('Parabola' in type(j.Geometry[k]).__name__ or 'Hyperbola' in type(j.Gm[k]).__name__\
- # or 'Ellipse' in type(j.Geometry[k]).__name__):
- elif (not use_discretize) and (accept_spline) and ('Ellipse' in type(Gm[k]).__name__):
- ## toBiArcs
- # or 'Ellipse' in type(j.Geometry[k]).__name__ ## Ellipses are not well approximated by Splines
+ # or 'Ellipse' in type(j.Geometry[k]).__name__):
+ elif (not use_discretize) and (accept_spline) and ("Ellipse" in type(Gm[k]).__name__):
+ ## toBiArcs
+ # or 'Ellipse' in type(j.Geometry[k]).__name__ ## Ellipses are not well approximated by Splines
gk = Gm[k]
- bs = gk.toBSpline() # (tolerance, maxSegments, maxDegree)
+ bs = gk.toBSpline() # (tolerance, maxSegments, maxDegree)
gds = bs.toBiArcs(precision)
- # import kicadStepUptools; import importlib; importlib.reload(kicadStepUptools)
- #;kicadStepUptools.open(u"C:/Temp/bspline.kicad_pcb")
- #for g in gds:
+ # import kicadStepUptools; import importlib; importlib.reload(kicadStepUptools)
+ # ;kicadStepUptools.open(u"C:/Temp/bspline.kicad_pcb")
+ # for g in gds:
# print(str(g))
- #stop
+ # stop
for g in gds:
# s = g.toShape() #needed to fix some issue on sketch geometry building
# outline.append([
# 'arc',
- # g.Radius,
+ # g.Radius,
# s.Edges[0].Curve.Center.x,
# s.Edges[0].Curve.Center.y,
- # g.FirstParameter,
+ # g.FirstParameter,
# g.LastParameter,
# g.Axis[0],
# g.Axis[1],
@@ -20304,30 +22164,32 @@ def getBoardOutline():
# s.Edges[0].Vertexes[1].Point,
# s.Edges[0].Orientation,
# j.Label
- # ])
+ # ])
# #Part.show(s)
- outline.append([
- 'arc',
- g.Radius,
- g.Center.x,
- g.Center.y,
- g.FirstParameter,
- g.LastParameter,
- g.Axis[0],
- g.Axis[1],
- g.Axis[2],
- g,
- g.StartPoint,
- g.EndPoint,
- 'Forward',
- j.Label
- ])
-
- #elif (accept_spline) and ('Parabola' in type(j.Geometry[k]).__name__ or 'Hyperbola' in type(j.Geometry[k]).__name__):
+ outline.append(
+ [
+ "arc",
+ g.Radius,
+ g.Center.x,
+ g.Center.y,
+ g.FirstParameter,
+ g.LastParameter,
+ g.Axis[0],
+ g.Axis[1],
+ g.Axis[2],
+ g,
+ g.StartPoint,
+ g.EndPoint,
+ "Forward",
+ j.Label,
+ ],
+ )
+
+ # elif (accept_spline) and ('Parabola' in type(j.Geometry[k]).__name__ or 'Hyperbola' in type(j.Geometry[k]).__name__):
# # or 'Ellipse' in type(j.Geometry[k]).__name__ ## Ellipses are not well approximated by Splines
# bs = j.Geometry[k]
- # bs = bs.approximateBSpline(edge_tolerance,maxSegment,maxDegree) # (tolerance, maxSegments, maxDegree)
- # bezier_list_tmp.extend(bs.toBezier())
+ # bs = bs.approximateBSpline(edge_tolerance,maxSegment,maxDegree) # (tolerance, maxSegments, maxDegree)
+ # bezier_list_tmp.extend(bs.toBezier())
# tmpGeo = []
# for bc in bezier_list_tmp:
# print("%s (degree : %d / nb poles : %d)"%(bc, bc.Degree, bc.NbPoles))
@@ -20364,278 +22226,299 @@ def getBoardOutline():
# j.Label
# ])
else: ## dropped ... it shouldn't arrive here
- #print j.Geometry[k],'; not supported'
- to_discretize.append(k) #to_discretize.append(k, j.Label)
- str_geom=str(Gm[k])
- if 'ArcOfEllipse' in str_geom:
- str_geom='ArcOfEllipse'
- elif 'ArcOfParabola' in str_geom:
- str_geom='ArcOfParabola'
- elif 'ArcOfHyperbola' in str_geom:
- str_geom='ArcOfHyperbola'
- if str_geom not in not_supported:
- if 'Vector' not in str_geom:
- not_supported=not_supported + str_geom.strip('<').strip('>').strip(' object')+'; '
- #continue
+ # print j.Geometry[k],'; not supported'
+ to_discretize.append(k) # to_discretize.append(k, j.Label)
+ str_geom = str(Gm[k])
+ if "ArcOfEllipse" in str_geom:
+ str_geom = "ArcOfEllipse"
+ elif "ArcOfParabola" in str_geom:
+ str_geom = "ArcOfParabola"
+ elif "ArcOfHyperbola" in str_geom:
+ str_geom = "ArcOfHyperbola"
+ if str_geom not in not_supported and "Vector" not in str_geom:
+ not_supported = not_supported + str_geom.strip("<").strip(">").strip(" object") + "; "
+ # continue
##break
except Exception as e:
- exc_type, exc_obj, exc_tb = sys.exc_info()
+ exc_type, _exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
- FreeCAD.Console.PrintWarning('1. ' + str(e) + "\n")
- FreeCAD.Console.PrintWarning('error class: '+str(exc_type)+'\nfile name: '+str(fname)+'\nerror @line: '+str(exc_tb.tb_lineno)+'\nerror value: '+str(e.args[0])+'\n')
+ FreeCAD.Console.PrintWarning("1. " + str(e) + "\n")
+ FreeCAD.Console.PrintWarning(
+ "error class: "
+ + str(exc_type)
+ + "\nfile name: "
+ + str(fname)
+ + "\nerror @line: "
+ + str(exc_tb.tb_lineno)
+ + "\nerror value: "
+ + str(e.args[0])
+ + "\n",
+ )
# print (to_discretize)
# stop
return outline, not_supported, to_discretize, construction_geom
+
+
##
-def createEdge(edg,ofs,sklayer=None,pcb_ver=None):
+def createEdge(edg, ofs, sklayer=None, pcb_ver=None):
global edge_width, maxRadius
-
- #print edg
- k_edg=''
+
+ # print edg
+ k_edg = ""
if edge_width is None:
- edge_width=0.16
- #def getMinX(self, x):
+ edge_width = 0.16
+ # def getMinX(self, x):
# if x < self.minX:
# self.minX = x
- #
- #def getMinY(self, y):
+ #
+ # def getMinY(self, y):
# if y < self.minY:
# self.minY = y
- if sklayer is None:
- layer='Edge.Cuts'
- else:
- layer = sklayer
- if edg[0] == 'line':
+ layer = "Edge.Cuts" if sklayer is None else sklayer
+ if edg[0] == "line":
if pcb_ver is None or pcb_ver < 20211014:
- k_edg = " (gr_line (start {0:.6f} {1:.6f}) (end {2:.6f} {3:.6f}) (angle 90) (layer {5}) (width {4}))"\
- .format(edg[1]+ofs[0], -edg[2]+ofs[1], edg[3]+ofs[0], -edg[4]+ofs[1], edge_width, layer)
- #k_edg +=os.linesep
- #.format('{0:.10f}').format(edg[1] + abs(0), '{0:.10f}').format(edg[2] + abs(0), '{0:.10f}').format(edg[3] + abs(0), '{0:.10f}').format(edg[4] + abs(0), 'Edge.Cuts', edge_width)
+ k_edg = f" (gr_line (start {edg[1] + ofs[0]:.6f} {-edg[2] + ofs[1]:.6f}) (end {edg[3] + ofs[0]:.6f} {-edg[4] + ofs[1]:.6f}) (angle 90) (layer {layer}) (width {edge_width}))"
+ # k_edg +=os.linesep
+ # .format('{0:.10f}').format(edg[1] + abs(0), '{0:.10f}').format(edg[2] + abs(0), '{0:.10f}').format(edg[3] + abs(0), '{0:.10f}').format(edg[4] + abs(0), 'Edge.Cuts', edge_width)
else:
- k_edg = " (gr_line (start {0:.6f} {1:.6f}) (end {2:.6f} {3:.6f}) (layer {5}) (width {4}))"\
- .format(edg[1]+ofs[0], -edg[2]+ofs[1], edg[3]+ofs[0], -edg[4]+ofs[1], edge_width, layer)
- elif edg[0] == 'circle':
- k_edg = " (gr_circle (center {0:.6f} {1:.6f}) (end {2:.6f} {1:.6f}) (layer {4}) (width {3}))".format(edg[2]+ofs[0], -edg[3]+ofs[1], edg[2]+ofs[0]-edg[1], edge_width, layer)
- #k_edg +=os.linesep
- #.format(
- #'{0:.10f}'.format(i[1] + abs(self.minX)), '{0:.10f}'.format(i[2] + abs(self.minY)), '{0:.10f}'.format(
+ k_edg = f" (gr_line (start {edg[1] + ofs[0]:.6f} {-edg[2] + ofs[1]:.6f}) (end {edg[3] + ofs[0]:.6f} {-edg[4] + ofs[1]:.6f}) (layer {layer}) (width {edge_width}))"
+ elif edg[0] == "circle":
+ k_edg = f" (gr_circle (center {edg[2] + ofs[0]:.6f} {-edg[3] + ofs[1]:.6f}) (end {edg[2] + ofs[0] - edg[1]:.6f} {-edg[3] + ofs[1]:.6f}) (layer {layer}) (width {edge_width}))"
+ # k_edg +=os.linesep
+ # .format(
+ #'{0:.10f}'.format(i[1] + abs(self.minX)), '{0:.10f}'.format(i[2] + abs(self.minY)), '{0:.10f}'.format(
# self.addCircle(edg[1:], 'Edge.Cuts', 0.01)
- elif edg[0] == 'arc':
- #print edg
- #print 2*pi
- #use_rotation=False
- #if abs(abs(edg[5])-2*pi) <= edge_tolerance:
+ elif edg[0] == "arc":
+ # print edg
+ # print 2*pi
+ # use_rotation=False
+ # if abs(abs(edg[5])-2*pi) <= edge_tolerance:
# print '2PI'
# use_rotation=True
- radius = edg[1] #radius
- xs = edg[2] #center x
- ys = (edg[3]) * (-1) #center y
- #mp = DraftGeomUtils.findMidpoint(self.circle.Edges[0])
- #if 0: #use_rotation:
+ edg[1] # radius
+ xs = edg[2] # center x
+ ys = (edg[3]) * (-1) # center y
+ # mp = DraftGeomUtils.findMidpoint(self.circle.Edges[0])
+ # if 0: #use_rotation:
# sayerr('2PI')
# sayerr('check edge orientation!!!')
# #eA = edg[4]+pi
# #sA = edg[5]+pi
# eA = edg[4]-pi/2
# sA = edg[5]-pi/2
- #else:
+ # else:
sA = edg[4]
eA = edg[5]
- axisX = edg[6]
- axisY = edg[7]
- axisZ = edg[8]
-
- angle = degrees(sA - eA) # * (-1)
+ edg[6]
+ edg[7]
+ edg[8]
+
+ angle = degrees(sA - eA) # * (-1)
# sayerr(angle)
-
+
##x1 = radius * cos(sA) + xs
##y1 = (radius * sin(sA)) * (-1) + ys
- #xs = edg[11][0]
- #ys = (edg[11][1]) * (-1)
+ # xs = edg[11][0]
+ # ys = (edg[11][1]) * (-1)
## sA = atan2(edg[10][1]-edg[3], edg[10][0]-edg[2])
## eA = atan2(edg[11][1]-edg[3], edg[11][0]-edg[2])
# sayerr(edg[12])
-
- x1 = edg[10][0]
- y1 = (edg[10][1]) * (-1)
- x2 = edg[11][0]
- y2 = (edg[11][1]) * (-1)
-
- #y1 = (radius * sin(sA)) * + ys
- #print axisX, axisY,axisZ
- #print ('coord xs, ys, x1, y1 ', xs,';', ys,';', x1,';', y1,';',angle)
- #for i,e in enumerate(edg):
+
+ x1 = edg[10][0]
+ y1 = (edg[10][1]) * (-1)
+ x2 = edg[11][0]
+ y2 = (edg[11][1]) * (-1)
+
+ # y1 = (radius * sin(sA)) * + ys
+ # print axisX, axisY,axisZ
+ # print ('coord xs, ys, x1, y1 ', xs,';', ys,';', x1,';', y1,';',angle)
+ # for i,e in enumerate(edg):
# print ('param edg['+str(i)+']='+str(edg[i]))
- #if angle > 180:
+ # if angle > 180:
# angle = 360 - angle
- #self.getMinX(xs)
- #self.getMinY(ys)
- #self.getMinX(x1)
- #self.getMinY(y1)
+ # self.getMinX(xs)
+ # self.getMinY(ys)
+ # self.getMinX(x1)
+ # self.getMinY(y1)
# Draft.makePoint(xs, -ys, 0)
# Draft.makePoint(x1, -y1, 0)
# #Draft.makePoint(mp[0],mp[1],mp[2])
# Draft.makePoint(x2, -y2, 0)
-
+
if abs(xs) > maxRadius or abs(ys) > maxRadius:
if pcb_ver is None or pcb_ver < 20211014:
- k_edg = " (gr_line (start {0:.6f} {1:.6f}) (end {2:.6f} {3:.6f}) (angle 0) (layer {5}) (width {4}))"\
- .format(x1+ofs[0], y1+ofs[1], x2+ofs[0], y2+ofs[1], edge_width, layer)
- #k_edg = " (gr_line (start {0} {1}) (end {2} {3}) (angle 90) (layer {5}) (width {4}))"\
+ k_edg = f" (gr_line (start {x1 + ofs[0]:.6f} {y1 + ofs[1]:.6f}) (end {x2 + ofs[0]:.6f} {y2 + ofs[1]:.6f}) (angle 0) (layer {layer}) (width {edge_width}))"
+ # k_edg = " (gr_line (start {0} {1}) (end {2} {3}) (angle 90) (layer {5}) (width {4}))"\
# .format(edg[1]+ofs[0], -edg[2]+ofs[1], edg[3]+ofs[0], -edg[4]+ofs[1], edge_width, 'Edge.Cuts')
- #print xs + ofs[0]
- #stop
+ # print xs + ofs[0]
+ # stop
else:
- k_edg = " (gr_line (start {0:.6f} {1:.6f}) (end {2:.6f} {3:.6f}) (layer {5}) (width {4}))"\
- .format(x1+ofs[0], y1+ofs[1], x2+ofs[0], y2+ofs[1], edge_width, layer)
+ k_edg = f" (gr_line (start {x1 + ofs[0]:.6f} {y1 + ofs[1]:.6f}) (end {x2 + ofs[0]:.6f} {y2 + ofs[1]:.6f}) (layer {layer}) (width {edge_width}))"
+ elif pcb_ver is None or pcb_ver < 20211014:
+ # self.pcbElem.append(['gr_arc', xs, ys, x1, y1, curve, width, layer])
+ k_edg = f" (gr_arc (start {xs + ofs[0]:.6f} {ys + ofs[1]:.6f}) (end {x1 + ofs[0]:.6f} {y1 + ofs[1]:.6f}) (angle {angle:.6f}) (layer {layer}) (width {edge_width}))"
else:
- if pcb_ver is None or pcb_ver < 20211014:
- #self.pcbElem.append(['gr_arc', xs, ys, x1, y1, curve, width, layer])
- k_edg = " (gr_arc (start {0:.6f} {1:.6f}) (end {2:.6f} {3:.6f}) (angle {4:.6f}) (layer {6}) (width {5}))"\
- .format(xs+ofs[0], ys+ofs[1], x1+ofs[0], y1+ofs[1], angle, edge_width, layer)
- else:
- #stop
- # print(angle)
- # ep = rotatePoint(radius,sA,angle,[x1,y1])
- # print(ep[0],ep[1])
- mp = mid_point(Base.Vector(x1,y1,0),Base.Vector(x2,y2,0),angle)
- # Draft.makePoint(x1,y1,0)
- # FreeCAD.ActiveDocument.ActiveObject.ViewObject.PointColor=(1.0,0.0,0.0,0.0)
- # Draft.makePoint(x2,y2,0)
- # FreeCAD.ActiveDocument.ActiveObject.ViewObject.PointColor=(0.0,1.0,0.0,0.0)
- # Draft.makePoint(mp[0],mp[1],0)
- # FreeCAD.ActiveDocument.ActiveObject.ViewObject.PointColor=(0.0,0.0,1.0,0.0)
- # Part.show(Part.Edge(Part.Arc(FreeCAD.Base.Vector(x1, y1, 0), FreeCAD.Base.Vector(mp[0],mp[1], 0), FreeCAD.Base.Vector(x2, y2, 0))))
- # print(mp[0],mp[1])
- k_edg = " (gr_arc (start {0:.6f} {1:.6f}) (mid {2:.6f} {3:.6f}) (end {4:.6f} {5:.6f}) (layer {7}) (width {6}))"\
- .format(x2+ofs[0], y2+ofs[1], mp[0]+ofs[0], mp[1]+ofs[1], x1+ofs[0], y1+ofs[1], edge_width, layer)
- #.format(xs+ofs[0], ys+ofs[1], mp[0]+ofs[0], mp[1]+ofs[1], x1+ofs[0], y1+ofs[1], edge_width, layer)
- #print(k_edg)
- #stop
+ # stop
+ # print(angle)
+ # ep = rotatePoint(radius,sA,angle,[x1,y1])
+ # print(ep[0],ep[1])
+ mp = mid_point(Base.Vector(x1, y1, 0), Base.Vector(x2, y2, 0), angle)
+ # Draft.makePoint(x1,y1,0)
+ # FreeCAD.ActiveDocument.ActiveObject.ViewObject.PointColor=(1.0,0.0,0.0,0.0)
+ # Draft.makePoint(x2,y2,0)
+ # FreeCAD.ActiveDocument.ActiveObject.ViewObject.PointColor=(0.0,1.0,0.0,0.0)
+ # Draft.makePoint(mp[0],mp[1],0)
+ # FreeCAD.ActiveDocument.ActiveObject.ViewObject.PointColor=(0.0,0.0,1.0,0.0)
+ # Part.show(Part.Edge(Part.Arc(FreeCAD.Base.Vector(x1, y1, 0), FreeCAD.Base.Vector(mp[0],mp[1], 0), FreeCAD.Base.Vector(x2, y2, 0))))
+ # print(mp[0],mp[1])
+ k_edg = f" (gr_arc (start {x2 + ofs[0]:.6f} {y2 + ofs[1]:.6f}) (mid {mp[0] + ofs[0]:.6f} {mp[1] + ofs[1]:.6f}) (end {x1 + ofs[0]:.6f} {y1 + ofs[1]:.6f}) (layer {layer}) (width {edge_width}))"
+ # .format(xs+ofs[0], ys+ofs[1], mp[0]+ofs[0], mp[1]+ofs[1], x1+ofs[0], y1+ofs[1], edge_width, layer)
+ # print(k_edg)
+ # stop
# self.addArc(edg[1:], 'Edge.Cuts', 0.01)
- elif edg[0] == 'spline':
- k_edg = " (gr_curve (pts (xy {0:.6f} {1:.6f}) (xy {2:.6f} {3:.6f}) (xy {4:.6f} {5:.6f}) (xy {6:.6f} {7:.6f})) (layer {9}) (width {8}))"\
- .format(edg[1]+ofs[0], -edg[2]+ofs[1], edg[3]+ofs[0], -edg[4]+ofs[1], edg[5]+ofs[0], -edg[6]+ofs[1], edg[7]+ofs[0], -edg[8]+ofs[1], edge_width, layer)
+ elif edg[0] == "spline":
+ k_edg = f" (gr_curve (pts (xy {edg[1] + ofs[0]:.6f} {-edg[2] + ofs[1]:.6f}) (xy {edg[3] + ofs[0]:.6f} {-edg[4] + ofs[1]:.6f}) (xy {edg[5] + ofs[0]:.6f} {-edg[6] + ofs[1]:.6f}) (xy {edg[7] + ofs[0]:.6f} {-edg[8] + ofs[1]:.6f})) (layer {layer}) (width {edge_width}))"
# (pts (xy 151.983691 88.782809) (xy 152.805595 84.674685) (xy 148.40623 80.726614) (xy 144.40069 81.955321)) (layer Edge.Cuts) (width 0.2))
-
+
return k_edg
+
+
##
-def createFp(edg,ofs,layer, edge_thick):
+def createFp(edg, ofs, layer, edge_thick):
global edge_width, maxRadius
-
- #print edg
- k_edg=''
- #if edge_width is None:
+
+ # print edg
+ k_edg = ""
+ # if edge_width is None:
# edge_width=0.16
- #def getMinX(self, x):
+ # def getMinX(self, x):
# if x < self.minX:
# self.minX = x
- #
- #def getMinY(self, y):
+ #
+ # def getMinY(self, y):
# if y < self.minY:
# self.minY = y
## writing fp
- ln='fp_line'
- ac='fp_arc'
- cr='fp_circle'
- if edg[0] == 'line':
- if 0: #abs(edg[1]+ofs[0])>500 or abs(edg[2]+ofs[1])>500:
- #print edg
+ ln = "fp_line"
+ ac = "fp_arc"
+ cr = "fp_circle"
+ if edg[0] == "line":
+ if 0: # abs(edg[1]+ofs[0])>500 or abs(edg[2]+ofs[1])>500:
+ # print edg
stop
- k_edg = " ("+ln+" (start {0:.6f} {1:.6f}) (end {2:.6f} {3:.6f}) (angle 90) (layer {5}) (width {4}))"\
- .format(edg[1]+ofs[0], -edg[2]+ofs[1], edg[3]+ofs[0], -edg[4]+ofs[1], edge_thick, layer)
+ k_edg = (
+ " ("
+ + ln
+ + f" (start {edg[1] + ofs[0]:.6f} {-edg[2] + ofs[1]:.6f}) (end {edg[3] + ofs[0]:.6f} {-edg[4] + ofs[1]:.6f}) (angle 90) (layer {layer}) (width {edge_thick}))"
+ )
else:
- k_edg = " ("+ln+" (start {0:.6f} {1:.6f}) (end {2:.6f} {3:.6f}) (layer {5}) (width {4}))"\
- .format(edg[1]+ofs[0], -edg[2]+ofs[1], edg[3]+ofs[0], -edg[4]+ofs[1], edge_thick, layer)
- #k_edg +=os.linesep
- #.format('{0:.10f}').format(edg[1] + abs(0), '{0:.10f}').format(edg[2] + abs(0), '{0:.10f}').format(edg[3] + abs(0), '{0:.10f}').format(edg[4] + abs(0), 'Edge.Cuts', edge_width)
- elif edg[0] == 'circle':
- k_edg = " ("+cr+" (center {0:.6f} {1:.6f}) (end {2:.6f} {1:.6f}) (layer {4}) (width {3}))".format(edg[2]+ofs[0], -edg[3]+ofs[1], edg[2]+ofs[0]-edg[1], edge_thick, layer)
- #k_edg +=os.linesep
- #.format(
- #'{0:.10f}'.format(i[1] + abs(self.minX)), '{0:.10f}'.format(i[2] + abs(self.minY)), '{0:.10f}'.format(
+ k_edg = (
+ " ("
+ + ln
+ + f" (start {edg[1] + ofs[0]:.6f} {-edg[2] + ofs[1]:.6f}) (end {edg[3] + ofs[0]:.6f} {-edg[4] + ofs[1]:.6f}) (layer {layer}) (width {edge_thick}))"
+ )
+ # k_edg +=os.linesep
+ # .format('{0:.10f}').format(edg[1] + abs(0), '{0:.10f}').format(edg[2] + abs(0), '{0:.10f}').format(edg[3] + abs(0), '{0:.10f}').format(edg[4] + abs(0), 'Edge.Cuts', edge_width)
+ elif edg[0] == "circle":
+ k_edg = (
+ " ("
+ + cr
+ + f" (center {edg[2] + ofs[0]:.6f} {-edg[3] + ofs[1]:.6f}) (end {edg[2] + ofs[0] - edg[1]:.6f} {-edg[3] + ofs[1]:.6f}) (layer {layer}) (width {edge_thick}))"
+ )
+ # k_edg +=os.linesep
+ # .format(
+ #'{0:.10f}'.format(i[1] + abs(self.minX)), '{0:.10f}'.format(i[2] + abs(self.minY)), '{0:.10f}'.format(
# self.addCircle(edg[1:], 'Edge.Cuts', 0.01)
- elif edg[0] == 'arc':
- #print edg
- #print 2*pi
- #use_rotation=False
- #if abs(abs(edg[5])-2*pi) <= edge_tolerance:
+ elif edg[0] == "arc":
+ # print edg
+ # print 2*pi
+ # use_rotation=False
+ # if abs(abs(edg[5])-2*pi) <= edge_tolerance:
# print '2PI'
# use_rotation=True
- radius = edg[1]
+ edg[1]
xs = edg[2]
ys = (edg[3]) * (-1)
- #if 0: #use_rotation:
+ # if 0: #use_rotation:
# sayerr('2PI')
# sayerr('check edge orientation!!!')
# #eA = edg[4]+pi
# #sA = edg[5]+pi
# eA = edg[4]-pi/2
# sA = edg[5]-pi/2
- #else:
+ # else:
sA = edg[4]
eA = edg[5]
- axisX = edg[6]
- axisY = edg[7]
- axisZ = edg[8]
-
- angle = degrees(sA - eA) # * (-1)
+ edg[6]
+ edg[7]
+ edg[8]
+
+ angle = degrees(sA - eA) # * (-1)
# sayerr(angle)
-
+
##x1 = radius * cos(sA) + xs
##y1 = (radius * sin(sA)) * (-1) + ys
- #xs = edg[11][0]
- #ys = (edg[11][1]) * (-1)
+ # xs = edg[11][0]
+ # ys = (edg[11][1]) * (-1)
## sA = atan2(edg[10][1]-edg[3], edg[10][0]-edg[2])
## eA = atan2(edg[11][1]-edg[3], edg[11][0]-edg[2])
# sayerr(edg[12])
-
- if 1: #angle ==< 0:
- x1 = edg[10][0]
- y1 = (edg[10][1]) * (-1)
- x2 = edg[11][0]
- y2 = (edg[11][1]) * (-1)
+
+ if 1: # angle ==< 0:
+ x1 = edg[10][0]
+ y1 = (edg[10][1]) * (-1)
+ x2 = edg[11][0]
+ y2 = (edg[11][1]) * (-1)
else:
- x1 = edg[11][0]
- y1 = (edg[11][1]) * (-1)
-
- #y1 = (radius * sin(sA)) * + ys
- #print axisX, axisY,axisZ
- #print 'coord xs, ys, x1, y1 ', xs,';', ys,';', x1,';', y1,';',angle
-
- #if angle > 180:
+ x1 = edg[11][0]
+ y1 = (edg[11][1]) * (-1)
+
+ # y1 = (radius * sin(sA)) * + ys
+ # print axisX, axisY,axisZ
+ # print 'coord xs, ys, x1, y1 ', xs,';', ys,';', x1,';', y1,';',angle
+
+ # if angle > 180:
# angle = 360 - angle
-
- #self.getMinX(xs)
- #self.getMinY(ys)
- #self.getMinX(x1)
- #self.getMinY(y1)
+
+ # self.getMinX(xs)
+ # self.getMinY(ys)
+ # self.getMinX(x1)
+ # self.getMinY(y1)
# Draft.makePoint(xs, -ys, 0)
# Draft.makePoint(x1, -y1, 0)
# #Draft.makePoint(mp[0],mp[1],mp[2])
# Draft.makePoint(x2, -y2, 0)
-
+
if abs(xs) > maxRadius or abs(ys) > maxRadius:
- k_edg = " ("+ln+" (start {0:.6f} {1:.6f}) (end {2:.6f} {3:.6f}) (layer {5}) (width {4}))"\
- .format(x1+ofs[0], y1+ofs[1], x2+ofs[0], y2+ofs[1], edge_thick, layer)
- #k_edg = " (gr_line (start {0} {1}) (end {2} {3}) (angle 90) (layer {5}) (width {4}))"\
+ k_edg = (
+ " ("
+ + ln
+ + f" (start {x1 + ofs[0]:.6f} {y1 + ofs[1]:.6f}) (end {x2 + ofs[0]:.6f} {y2 + ofs[1]:.6f}) (layer {layer}) (width {edge_thick}))"
+ )
+ # k_edg = " (gr_line (start {0} {1}) (end {2} {3}) (angle 90) (layer {5}) (width {4}))"\
# .format(edg[1]+ofs[0], -edg[2]+ofs[1], edg[3]+ofs[0], -edg[4]+ofs[1], edge_width, 'Edge.Cuts')
- #print xs + ofs[0]
- #stop
+ # print xs + ofs[0]
+ # stop
else:
- #self.pcbElem.append(['gr_arc', xs, ys, x1, y1, curve, width, layer])
- k_edg = " ("+ac+" (start {0:.6f} {1:.6f}) (end {2:.6f} {3:.6f}) (angle {4:.6f}) (layer {6}) (width {5}))"\
- .format(xs+ofs[0], ys+ofs[1], x1+ofs[0], y1+ofs[1], angle, edge_thick, layer)
- #.format(
+ # self.pcbElem.append(['gr_arc', xs, ys, x1, y1, curve, width, layer])
+ k_edg = (
+ " ("
+ + ac
+ + f" (start {xs + ofs[0]:.6f} {ys + ofs[1]:.6f}) (end {x1 + ofs[0]:.6f} {y1 + ofs[1]:.6f}) (angle {angle:.6f}) (layer {layer}) (width {edge_thick}))"
+ )
+ # .format(
# '{0:.10f}'.format(i[1] + abs(self.minX)), '{0:.10f}'.format(i[2] + abs(self.minY)), '{0:.10f}'.format(i[3] + abs(self.minX)), '{0:.10f}'.format(i[4] + abs(self.minY)), i[5], i[6], i[7]))
# self.addArc(edg[1:], 'Edge.Cuts', 0.01)
return k_edg
+
+
##
-def Discretize(skt_name,delete=None,dqt=None):
+
+def Discretize(skt_name, delete=None, dqt=None):
##http://forum.freecadweb.org/viewtopic.php?f=12&t=16336#p129468
##Discretizes the edge and returns a list of points.
##The function accepts keywords as argument:
@@ -20646,7 +22529,7 @@ def Discretize(skt_name,delete=None,dqt=None):
##discretize(QuasiDeflection=d) => gives a list of points with a maximum deflection 'd' to the edge (faster)
##discretize(Angular=a,Curvature=c,[Minimum=m]) => gives a list of points with an angular deflection of 'a'
##and a curvature deflection of 'c'. Optionally a minimum number of points
- ##can be set which by default is set to 2.
+ ##can be set which by default is set to 2.
global dvm, dqd, precision
@@ -20656,221 +22539,213 @@ def Discretize(skt_name,delete=None,dqt=None):
# #print dv
# if dv < 20:
# dv=20
- b=FreeCAD.ActiveDocument.getObject(skt_name)
- shp1=b.Shape.copy()
- #e = shp1.Edges[0].Curve
- #skList=[]
+ b = FreeCAD.ActiveDocument.getObject(skt_name)
+ shp1 = b.Shape.copy()
+ # e = shp1.Edges[0].Curve
+ # skList=[]
newShapeList = []
newShapes = []
for e in shp1.Edges:
- ##e = shp1.Edges[0] #.Curve
- #sayerr(e.Curve)
- #print DraftGeomUtils.geomType(e)
- #if isinstance(e.Curve,Part.BSplineCurve):
- # sayerr('geomType BSP')
- #Part.show(shp1)
- if isinstance(e.Curve,Part.BSplineCurve):
- say('found BSpline')
+ ##e = shp1.Edges[0] #.Curve
+ # sayerr(e.Curve)
+ # print DraftGeomUtils.geomType(e)
+ # if isinstance(e.Curve,Part.BSplineCurve):
+ # sayerr('geomType BSP')
+ # Part.show(shp1)
+ if isinstance(e.Curve, Part.BSplineCurve):
+ say("found BSpline")
edges = []
arcs = e.Curve.toBiArcs(precision)
- #print arcs
+ # print arcs
for i in arcs:
edges.append(Part.Edge(i))
w = Part.Wire([Part.Edge(i) for i in edges])
Part.show(w)
- w_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ w_name = FreeCAD.ActiveDocument.ActiveObject.Name
newShapeList.append(w_name)
- wn=FreeCAD.ActiveDocument.getObject(w_name)
+ wn = FreeCAD.ActiveDocument.getObject(w_name)
newShapes.append(wn)
# elif isinstance(e.Curve,Part.Ellipse):
# say('found Ellipse')
- else: #ellipses or other curves
- say('found Ellipse')
- #l=b.Shape.copy().discretize(dv)
- #l=b.Shape.copy().discretize(QuasiDeflection=0.02)
+ else: # ellipses or other curves
+ say("found Ellipse")
+ # l=b.Shape.copy().discretize(dv)
+ # l=b.Shape.copy().discretize(QuasiDeflection=0.02)
w = Part.Wire(e)
Part.show(w)
- w_name=FreeCAD.ActiveDocument.ActiveObject.Name
- #newShapeList.append(w_name)
- wn=FreeCAD.ActiveDocument.getObject(w_name)
- #newShapes.append(wn)
+ w_name = FreeCAD.ActiveDocument.ActiveObject.Name
+ # newShapeList.append(w_name)
+ wn = FreeCAD.ActiveDocument.getObject(w_name)
+ # newShapes.append(wn)
if dqt is None:
- l=wn.Shape.copy().discretize(QuasiDeflection=dqd)
+ l = wn.Shape.copy().discretize(QuasiDeflection=dqd)
else:
- l=wn.Shape.copy().discretize(QuasiDeflection=dqt)
- #l=b.Shape.copy().discretize(QuasiDeflection=dqd)
- f=Part.makePolygon(l)
+ l = wn.Shape.copy().discretize(QuasiDeflection=dqt)
+ # l=b.Shape.copy().discretize(QuasiDeflection=dqd)
+ f = Part.makePolygon(l)
Part.show(f)
- sh_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ sh_name = FreeCAD.ActiveDocument.ActiveObject.Name
newShapeList.append(sh_name)
newShapes.append(f)
FreeCAD.ActiveDocument.removeObject(w_name)
- FreeCAD.ActiveDocument.recompute()
-
+ FreeCAD.ActiveDocument.recompute()
+
## sketch = Draft.makeSketch(newShapes[0],autoconstraints=True)
- sketch = Draft.makeSketch(FreeCAD.ActiveDocument.getObject(newShapeList[0]),autoconstraints=True)
-
- #FreeCAD.ActiveDocument.ActiveObject.Label="Sketch_dxf"
- sname=FreeCAD.ActiveDocument.ActiveObject.Name
+ sketch = Draft.makeSketch(FreeCAD.ActiveDocument.getObject(newShapeList[0]), autoconstraints=True)
+
+ # FreeCAD.ActiveDocument.ActiveObject.Label="Sketch_dxf"
+ sname = FreeCAD.ActiveDocument.ActiveObject.Name
for w in newShapes[1:]:
- Draft.makeSketch([w],addTo=sketch)
- geom=[]
+ Draft.makeSketch([w], addTo=sketch)
+ geom = []
## recreating a correct geometry
for i in sketch.Geometry:
- if isinstance(i,Part.ArcOfCircle) and i.XAxis.x < 0:
- arc=Part.ArcOfCircle(i.Circle,i.FirstParameter+pi,i.LastParameter+pi)
+ if isinstance(i, Part.ArcOfCircle) and i.XAxis.x < 0:
+ arc = Part.ArcOfCircle(i.Circle, i.FirstParameter + pi, i.LastParameter + pi)
arc.XAxis.x = -arc.XAxis.x
geom.append(arc)
else:
- geom.append(i)
- tsk= FreeCAD.activeDocument().addObject('Sketcher::SketchObject','Sketch_result')
+ geom.append(i)
+ tsk = FreeCAD.activeDocument().addObject("Sketcher::SketchObject", "Sketch_result")
tsk.addGeometry(geom)
- tsk.Placement=FreeCAD.ActiveDocument.getObject(sname).Placement
+ tsk.Placement = FreeCAD.ActiveDocument.getObject(sname).Placement
FreeCAD.ActiveDocument.removeObject(sname)
- #print tsk.Geometry
+ # print tsk.Geometry
##for w in newShapes[1:]:
- ## Draft.makeSketch([w],addTo=sketch)
- #stop
- #for wire in wires:
+ ## Draft.makeSketch([w],addTo=sketch)
+ # stop
+ # for wire in wires:
# FreeCAD.ActiveDocument.removeObject(wire.Name)
for wnm in newShapeList:
FreeCAD.ActiveDocument.removeObject(wnm)
if delete is None:
FreeCAD.ActiveDocument.removeObject(skt_name)
- FreeCAD.ActiveDocument.recompute()
- s_name=tsk.Name
-
- #else: #ellipses
- # #l=b.Shape.copy().discretize(dv)
- # #l=b.Shape.copy().discretize(QuasiDeflection=0.02)
- # l=b.Shape.copy().discretize(QuasiDeflection=dqd)
- # f=Part.makePolygon(l)
- # Part.show(f)
- # sh_name=FreeCAD.ActiveDocument.ActiveObject.Name
- # FreeCAD.ActiveDocument.recompute()
- # Draft.makeSketch(FreeCAD.ActiveDocument.getObject(sh_name),autoconstraints=True)
- # s_name=FreeCAD.ActiveDocument.ActiveObject.Name
- # FreeCAD.ActiveDocument.removeObject(sh_name)
- # FreeCAD.ActiveDocument.removeObject(skt_name)
- # FreeCAD.ActiveDocument.recompute()
-
-
- return s_name
- #stop
+ FreeCAD.ActiveDocument.recompute()
+ return tsk.Name
+
+ # else: #ellipses
+ # #l=b.Shape.copy().discretize(dv)
+ # #l=b.Shape.copy().discretize(QuasiDeflection=0.02)
+ # l=b.Shape.copy().discretize(QuasiDeflection=dqd)
+ # f=Part.makePolygon(l)
+ # Part.show(f)
+ # sh_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ # FreeCAD.ActiveDocument.recompute()
+ # Draft.makeSketch(FreeCAD.ActiveDocument.getObject(sh_name),autoconstraints=True)
+ # s_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ # FreeCAD.ActiveDocument.removeObject(sh_name)
+ # FreeCAD.ActiveDocument.removeObject(skt_name)
+ # FreeCAD.ActiveDocument.recompute()
+
+ # stop
+
##
def remove_basic_geom(c_name, to_disc):
-
- s=FreeCAD.ActiveDocument.getObject(c_name)
- geoL=len(FreeCAD.ActiveDocument.getObject(c_name).Geometry)
- #print 'to discretize'
- #print to_disc
- to_disc_str=[]
- for j in range (len(to_disc)):
+
+ s = FreeCAD.ActiveDocument.getObject(c_name)
+ geoL = len(FreeCAD.ActiveDocument.getObject(c_name).Geometry)
+ # print 'to discretize'
+ # print to_disc
+ to_disc_str = []
+ for j in range(len(to_disc)):
to_disc_str.append(str(to_disc[j]))
- #print to_disc_str
- #print 'geo',' ', App.ActiveDocument.getObject(c_name).Geometry
- #print 'oldgeo',' ', App.ActiveDocument.getObject("PCB_Sketch").Geometry
- #stop
- #print 'removing'
- #for i in range (geoL-1,0,-1):
- for i in range (geoL-1,-1,-1):
- #print 's.geom'
- #if str(s.Geometry[i-1]) in to_disc_str:
+ # print to_disc_str
+ # print 'geo',' ', App.ActiveDocument.getObject(c_name).Geometry
+ # print 'oldgeo',' ', App.ActiveDocument.getObject("PCB_Sketch").Geometry
+ # stop
+ # print 'removing'
+ # for i in range (geoL-1,0,-1):
+ for i in range(geoL - 1, -1, -1):
+ # print 's.geom'
+ # if str(s.Geometry[i-1]) in to_disc_str:
# print 'found geo to disc'
- #else:
- #print str(s.Geometry[i]), ';;'
+ # else:
+ # print str(s.Geometry[i]), ';;'
if str(s.Geometry[i]) not in to_disc_str:
- if hasattr(s,'GeometryFacadeList'):
- Gm = s.GeometryFacadeList
- else:
- Gm = s.Geometry
- #if hasattr(Gm[i],'Construction'):
+ Gm = s.GeometryFacadeList if hasattr(s, "GeometryFacadeList") else s.Geometry
+ # if hasattr(Gm[i],'Construction'):
# if not Gm[i].Construction:
if isConstruction(Gm[i]):
- #print FreeCAD.ActiveDocument.getObject(c_name).Geometry[i]
+ # print FreeCAD.ActiveDocument.getObject(c_name).Geometry[i]
FreeCAD.ActiveDocument.getObject(c_name).delGeometry(i)
FreeCAD.ActiveDocument.recompute()
- #stop
- #if i not in
- #App.ActiveDocument.getObject("PCB_Sketch").delGeometry(0, 3, 4, 10, 11, 12)
+ # stop
+ # if i not in
+ # App.ActiveDocument.getObject("PCB_Sketch").delGeometry(0, 3, 4, 10, 11, 12)
+
+
##
def split_basic_geom(c_name, to_disc):
-
- s=FreeCAD.ActiveDocument.getObject(c_name)
- geoL=len(FreeCAD.ActiveDocument.getObject(c_name).Geometry)
+
+ s = FreeCAD.ActiveDocument.getObject(c_name)
+ geoL = len(FreeCAD.ActiveDocument.getObject(c_name).Geometry)
geoB = []
- #print 'to discretize'
- #print to_disc
- to_disc_str=[]
- for j in range (len(to_disc)):
+ # print 'to discretize'
+ # print to_disc
+ to_disc_str = []
+ for j in range(len(to_disc)):
to_disc_str.append(str(to_disc[j]))
- #print to_disc_str
- #print 'geo',' ', App.ActiveDocument.getObject(c_name).Geometry
- #print 'oldgeo',' ', App.ActiveDocument.getObject("PCB_Sketch").Geometry
- #stop
- #print 'removing'
- #for i in range (geoL-1,0,-1):
- for i in range (geoL-1,-1,-1):
- #print 's.geom'
- #if str(s.Geometry[i-1]) in to_disc_str:
+ # print to_disc_str
+ # print 'geo',' ', App.ActiveDocument.getObject(c_name).Geometry
+ # print 'oldgeo',' ', App.ActiveDocument.getObject("PCB_Sketch").Geometry
+ # stop
+ # print 'removing'
+ # for i in range (geoL-1,0,-1):
+ for i in range(geoL - 1, -1, -1):
+ # print 's.geom'
+ # if str(s.Geometry[i-1]) in to_disc_str:
# print 'found geo to disc'
- #else:
- #print str(s.Geometry[i]), ';;'
+ # else:
+ # print str(s.Geometry[i]), ';;'
if str(s.Geometry[i]) not in to_disc_str:
- if hasattr(s,'GeometryFacadeList'):
- Gm = s.GeometryFacadeList
- else:
- Gm = s.Geometry
- #if hasattr(Gm[i],'Construction'):
+ Gm = s.GeometryFacadeList if hasattr(s, "GeometryFacadeList") else s.Geometry
+ # if hasattr(Gm[i],'Construction'):
# if not Gm[i].Construction:
if isConstruction(Gm[i]):
- #print FreeCAD.ActiveDocument.getObject(c_name).Geometry[i]
+ # print FreeCAD.ActiveDocument.getObject(c_name).Geometry[i]
geoB.append(FreeCAD.ActiveDocument.getObject(c_name).Geometry[i])
FreeCAD.ActiveDocument.getObject(c_name).delGeometry(i)
FreeCAD.ActiveDocument.recompute()
- #stop
- #if i not in
- #App.ActiveDocument.getObject("PCB_Sketch").delGeometry(0, 3, 4, 10, 11, 12)
+ # stop
+ # if i not in
+ # App.ActiveDocument.getObject("PCB_Sketch").delGeometry(0, 3, 4, 10, 11, 12)
return geoB
+
+
##
def check_geom(sk_name, ofs=None):
-
+
if ofs is None:
- ofs=[0,0]
- j=FreeCAD.ActiveDocument.getObject(sk_name)
- to_discretize=[]
- outline=[]
- foundBSP=False
- foundElly=False
- geo_all=''
+ ofs = [0, 0]
+ j = FreeCAD.ActiveDocument.getObject(sk_name)
+ to_discretize = []
+ outline = []
for k in range(len(j.Geometry)):
- foundGeo=False
- #print(type(j.Geometry[k]).__name__)
- if hasattr(j,'GeometryFacadeList'):
- Gm = j.GeometryFacadeList
- else:
- Gm = j.Geometry
- #if hasattr(Gm[k],'Construction'):
+ # print(type(j.Geometry[k]).__name__)
+ Gm = j.GeometryFacadeList if hasattr(j, "GeometryFacadeList") else j.Geometry
+ # if hasattr(Gm[k],'Construction'):
if isConstruction(Gm[k]):
- sayw('construnction skipped')
- #if Gm[k].Construction:
- #sayerr('construction skipped')
+ sayw("construnction skipped")
+ # if Gm[k].Construction:
+ # sayerr('construction skipped')
continue
- if 'Point' in type(j.Geometry[k]).__name__: #skipping points
- sayw('point skipped')
+ if "Point" in type(j.Geometry[k]).__name__: # skipping points
+ sayw("point skipped")
continue
- if 'LineSegment' in type(j.Geometry[k]).__name__:
- #if 'Line' in type(j.Geometry[k]).__name__:
- sk_ge=j.Geometry[k].toShape() #needed to fix some issue on sketch geometry building
- outline.append([
- 'line',
- sk_ge.Edges[0].Vertexes[0].Point.x+ofs[0],
- sk_ge.Edges[0].Vertexes[0].Point.y+ofs[1],
- sk_ge.Edges[0].Vertexes[1].Point.x+ofs[0],
- sk_ge.Edges[0].Vertexes[1].Point.y+ofs[1],
- j.Label
- ])
+ if "LineSegment" in type(j.Geometry[k]).__name__:
+ # if 'Line' in type(j.Geometry[k]).__name__:
+ sk_ge = j.Geometry[k].toShape() # needed to fix some issue on sketch geometry building
+ outline.append(
+ [
+ "line",
+ sk_ge.Edges[0].Vertexes[0].Point.x + ofs[0],
+ sk_ge.Edges[0].Vertexes[0].Point.y + ofs[1],
+ sk_ge.Edges[0].Vertexes[1].Point.x + ofs[0],
+ sk_ge.Edges[0].Vertexes[1].Point.y + ofs[1],
+ j.Label,
+ ],
+ )
# outline.append([
# 'line',
# j.Geometry[k].StartPoint.x+ofs[0],
@@ -20878,30 +22753,32 @@ def check_geom(sk_name, ofs=None):
# j.Geometry[k].EndPoint.x+ofs[0],
# j.Geometry[k].EndPoint.y+ofs[1]
# ])
- #elif type(j.Geometry[k]).__name__ == 'Circle':
- elif 'Circle' in type(j.Geometry[k]).__name__ and not 'ArcOfCircle' in type(j.Geometry[k]).__name__:
- sk_ge=j.Geometry[k].toShape() #needed to fix some issue on sketch geometry building
- outline.append([
- 'circle',
- sk_ge.Edges[0].Curve.Radius,
- sk_ge.Edges[0].Curve.Center.x+ofs[0],
- sk_ge.Edges[0].Curve.Center.y+ofs[1],
- j.Label
- ])
- #outline.append([
+ # elif type(j.Geometry[k]).__name__ == 'Circle':
+ elif "Circle" in type(j.Geometry[k]).__name__ and "ArcOfCircle" not in type(j.Geometry[k]).__name__:
+ sk_ge = j.Geometry[k].toShape() # needed to fix some issue on sketch geometry building
+ outline.append(
+ [
+ "circle",
+ sk_ge.Edges[0].Curve.Radius,
+ sk_ge.Edges[0].Curve.Center.x + ofs[0],
+ sk_ge.Edges[0].Curve.Center.y + ofs[1],
+ j.Label,
+ ],
+ )
+ # outline.append([
# 'circle',
# j.Geometry[k].Radius,
- # j.Geometry[k].Center.x+ofs[0],
+ # j.Geometry[k].Center.x+ofs[0],
# j.Geometry[k].Center.y+ofs[1]
- #])
- #elif type(j.Geometry[k]).__name__ == 'ArcOfCircle':
- elif 'ArcOfCircle' in type(j.Geometry[k]).__name__:
- #outline.append([
+ # ])
+ # elif type(j.Geometry[k]).__name__ == 'ArcOfCircle':
+ elif "ArcOfCircle" in type(j.Geometry[k]).__name__:
+ # outline.append([
# 'arc',
- # j.Geometry[k].Radius,
- # j.Geometry[k].Center.x+ofs[0],
- # j.Geometry[k].Center.y+ofs[1],
- # j.Geometry[k].FirstParameter+ofs[0],
+ # j.Geometry[k].Radius,
+ # j.Geometry[k].Center.x+ofs[0],
+ # j.Geometry[k].Center.y+ofs[1],
+ # j.Geometry[k].FirstParameter+ofs[0],
# j.Geometry[k].LastParameter+ofs[1],
# j.Geometry[k].Axis[0],
# j.Geometry[k].Axis[1],
@@ -20910,24 +22787,26 @@ def check_geom(sk_name, ofs=None):
# j.Shape.Edges[k].Vertexes[0].Point,
# j.Shape.Edges[k].Vertexes[1].Point,
# j.Shape.Edges[k].Orientation
- #])
- sk_ge=j.Geometry[k].toShape() #needed to fix some issue on sketch geometry building
- outline.append([
- 'arc',
- j.Geometry[k].Radius,
- sk_ge.Edges[0].Curve.Center.x+ofs[0],
- sk_ge.Edges[0].Curve.Center.y+ofs[1],
- j.Geometry[k].FirstParameter+ofs[0],
- j.Geometry[k].LastParameter+ofs[1],
- j.Geometry[k].Axis[0],
- j.Geometry[k].Axis[1],
- j.Geometry[k].Axis[2],
- j.Geometry[k],
- sk_ge.Edges[0].Vertexes[0].Point,
- sk_ge.Edges[0].Vertexes[1].Point,
- sk_ge.Edges[0].Orientation,
- j.Label
- ])
+ # ])
+ sk_ge = j.Geometry[k].toShape() # needed to fix some issue on sketch geometry building
+ outline.append(
+ [
+ "arc",
+ j.Geometry[k].Radius,
+ sk_ge.Edges[0].Curve.Center.x + ofs[0],
+ sk_ge.Edges[0].Curve.Center.y + ofs[1],
+ j.Geometry[k].FirstParameter + ofs[0],
+ j.Geometry[k].LastParameter + ofs[1],
+ j.Geometry[k].Axis[0],
+ j.Geometry[k].Axis[1],
+ j.Geometry[k].Axis[2],
+ j.Geometry[k],
+ sk_ge.Edges[0].Vertexes[0].Point,
+ sk_ge.Edges[0].Vertexes[1].Point,
+ sk_ge.Edges[0].Orientation,
+ j.Label,
+ ],
+ )
## maxRadius=3500
## sayerr(j.Geometry[k].Radius)
## stop
@@ -20939,11 +22818,11 @@ def check_geom(sk_name, ofs=None):
# sayerr('Xaxis2b')
# outline.append([
# 'arc',
- # i.Radius,
- # i.Center.x,
- # i.Center.y,
+ # i.Radius,
+ # i.Center.x,
+ # i.Center.y,
# i.LastParameter+pi,
- # i.FirstParameter+pi,
+ # i.FirstParameter+pi,
# -i.Axis[0],
# i.Axis[1],
# i.Axis[2],
@@ -20952,31 +22831,31 @@ def check_geom(sk_name, ofs=None):
# else:
# outline.append([
# 'arc',
- # i.Radius,
- # i.Center.x,
- # i.Center.y,
+ # i.Radius,
+ # i.Center.x,
+ # i.Center.y,
# i.LastParameter,
- # i.FirstParameter+pi,
+ # i.FirstParameter+pi,
# i.Axis[0],
# i.Axis[1],
# i.Axis[2],
# i
# ])
else:
- #print j.Geometry[k],'; not supported'
+ # print j.Geometry[k],'; not supported'
to_discretize.append(j.Geometry[k])
- #to_discretize.append(k)
- str_geom=str(j.Geometry[k])
- if 'ArcOfEllipse' in str_geom:
- str_geom='ArcOfEllipse'
- elif 'ArcOfParabola' in str_geom:
- str_geom='ArcOfParabola'
- elif 'ArcOfHyperbola' in str_geom:
- str_geom='ArcOfHyperbola'
- #continue
- ##break
- #print j.Geometry[k],'; not supported'
- #else:
+ # to_discretize.append(k)
+ str_geom = str(j.Geometry[k])
+ if "ArcOfEllipse" in str_geom:
+ str_geom = "ArcOfEllipse"
+ elif "ArcOfParabola" in str_geom:
+ str_geom = "ArcOfParabola"
+ elif "ArcOfHyperbola" in str_geom:
+ str_geom = "ArcOfHyperbola"
+ # continue
+ ##break
+ # print j.Geometry[k],'; not supported'
+ # else:
# str_geom=str(j.Geometry[k])
# if 'ArcOfEllipse' in str_geom:
# str_geom='ArcOfEllipse'
@@ -20993,76 +22872,81 @@ def check_geom(sk_name, ofs=None):
# foundGeom=True;foundBSP==False;foundElly==False
# if 'Vector' in str_geom:
# if foundBSP==True and foundGeom==False or foundElly==True and foundGeom==False:
- # to_discretize.append(j.Geometry[k])
+ # to_discretize.append(j.Geometry[k])
# #continue
##break
- #print to_discretize
- #stop
-
+ # print to_discretize
+ # stop
+
return outline, to_discretize
##
+
## getGridOrigin
def getGridOrigin(dt):
- match = re.search(r'\(grid_origin (.+?) (.+?)\)', dt, re.MULTILINE|re.DOTALL)
+ match = re.search(r"\(grid_origin (.+?) (.+?)\)", dt, re.MULTILINE | re.DOTALL)
if match is not None:
- return [float(match.group(1)), float(match.group(2))];
- else:
- #returning default top left corner value
- return [0.0,0.0]
+ return [float(match.group(1)), float(match.group(2))]
+ # returning default top left corner value
+ return [0.0, 0.0]
+
+
##
## getAuxOrigin
def getAuxOrigin(dt):
- match = re.search(r'\(aux_axis_origin (.+?) (.+?)\)', dt, re.MULTILINE|re.DOTALL)
+ match = re.search(r"\(aux_axis_origin (.+?) (.+?)\)", dt, re.MULTILINE | re.DOTALL)
if match is not None:
- return [float(match.group(1)), float(match.group(2))];
- else:
- # #returning default top left corner value
- # return [0.0,0.0]
- return None
+ return [float(match.group(1)), float(match.group(2))]
+ # #returning default top left corner value
+ # return [0.0,0.0]
+ return None
+
+
##
-def searchInsideFootprint (cnt, i): #not used atm
+def searchInsideFootprint(cnt, i): # not used atm
# check if the lines are inside a footprint... then they have to be skipped because they mixed fp_ and gr_ prefixes https://gitlab.com/kicad/code/kicad/-/issues/16660
- l=len(cnt)
+ l = len(cnt)
line = cnt[i]
- closed=False
- j=i
- open_p=0
- close_p=0
+ closed = False
+ j = i
+ open_p = 0
+ close_p = 0
# print (line + ' ' + str(i))
- if '(footprint' in line:
+ if "(footprint" in line:
# print ('fp ' + line + ' ' + str(i))
- open_p=line.count('(')
- close_p=line.count(')')
- j+=1
- while j < l and closed==False: # kv8 utilizzo il conteggio parentesi dalla prima alla chiusura o il parser
- line_next=cnt[j]
- open_p+=line_next.count('(')
- close_p+=line_next.count(')')
+ open_p = line.count("(")
+ close_p = line.count(")")
+ j += 1
+ while j < l and not closed: # kv8 utilizzo il conteggio parentesi dalla prima alla chiusura o il parser
+ line_next = cnt[j]
+ open_p += line_next.count("(")
+ close_p += line_next.count(")")
# print (line_next + ' ' + str(j) + ' open_p=' + str(open_p) + ' close_p=' + str(close_p))
if open_p == close_p:
- #print (line_next + ' closed fp')
- return j+1
- j+=1
+ # print (line_next + ' closed fp')
+ return j + 1
+ j += 1
else:
return i
-
+ return None
+
+
##
-def search_content(cnt, i,layer):
+def search_content(cnt, i, layer):
# first call include '(gr_line' in line or '(gr_curve' in line or '(gr_arc' in line or '(gr_circle' in line or '(gr_rect' in line or '(gr_poly' in line:
# offset,add_line = search_content(content,id,ssklayer)
# check if the lines are inside a footprint... then they have to be skipped because they mixed fp_ and gr_ prefixes https://gitlab.com/kicad/code/kicad/-/issues/16660
# kv8 Check if given Parentheses expression is balanced
- add_ln=True
- l=len(cnt)
- line = cnt[i]
- closed=False
- j=i
- found_tag=False
- open_p=0
- close_p=0
+ add_ln = True
+ l = len(cnt)
+ cnt[i]
+ closed = False
+ j = i
+ found_tag = False
+ open_p = 0
+ close_p = 0
## if '(layer' in line and '))' in line: #kv5
## if layer in line: #kv5
## add_ln = False
@@ -21074,35 +22958,44 @@ def search_content(cnt, i,layer):
## closed=True
## return add_ln, i
## # here if not kv5
- while j < l and closed==False: # kv6-kv8 Check if given Parentheses expression is balanced
- line_next=cnt[j]
- if '(gr_line' in line_next or '(gr_curve' in line_next or '(gr_arc' in line_next or '(gr_circle' in line_next or '(gr_rect' in line_next or '(gr_poly' in line_next:
- #starting group
- found_tag=True
- open_p+=line_next.count('(')
- close_p+=line_next.count(')')
- if '(layer' in line_next and layer in line_next:
+ while j < l and not closed: # kv6-kv8 Check if given Parentheses expression is balanced
+ line_next = cnt[j]
+ if (
+ "(gr_line" in line_next
+ or "(gr_curve" in line_next
+ or "(gr_arc" in line_next
+ or "(gr_circle" in line_next
+ or "(gr_rect" in line_next
+ or "(gr_poly" in line_next
+ ):
+ # starting group
+ found_tag = True
+ open_p += line_next.count("(")
+ close_p += line_next.count(")")
+ if "(layer" in line_next and layer in line_next:
add_ln = False
if open_p == close_p:
- #print (line_next + ' closed fp')
- return add_ln, j+1
- j+=1
- elif found_tag==True and closed==False:
- #line_next=cnt(j)
- open_p+=line_next.count('(')
- close_p+=line_next.count(')')
- if '(layer' in line_next and layer in line_next:
+ # print (line_next + ' closed fp')
+ return add_ln, j + 1
+ j += 1
+ elif found_tag and not closed:
+ # line_next=cnt(j)
+ open_p += line_next.count("(")
+ close_p += line_next.count(")")
+ if "(layer" in line_next and layer in line_next:
add_ln = False
if open_p == close_p:
- #print (line_next + ' closed fp')
- return add_ln, j+1
- #return j+1
- j+=1
- stop #we shouldn't arrive here
+ # print (line_next + ' closed fp')
+ return add_ln, j + 1
+ # return j+1
+ j += 1
+ stop # we shouldn't arrive here
+ return None
# return j, add_ln
+
##
-def export_pcb(fname=None,sklayer=None,skname=None):
+def export_pcb(fname=None, sklayer=None, skname=None):
global last_fp_path, test_flag, start_time
global configParser, configFilePath, start_time
global ignore_utf8, ignore_utf8_incfg, disable_PoM_Observer
@@ -21111,257 +23004,282 @@ def export_pcb(fname=None,sklayer=None,skname=None):
global original_filename, aux_orig, grid_orig
global off_x, off_y, maxRadius
global zfit, edge_width
-
- import fcad_parser
- from fcad_parser import KicadPCB,SexpList
- import kicad_parser
-
- sayw('exporting new pcb edges')
- doc=FreeCAD.ActiveDocument
- #filePath=last_pcb_path
- #fpath=filePath+os.sep+doc.Label+'.kicad_pcb'
- #sayerr('to '+fpath)
-
- #print fname
- if fname is None:
- fpath=original_filename
- else:
- fpath=fname
-
- sayerr('saving to '+fpath)
- #stop
-
+
+ sayw("exporting new pcb edges")
+ doc = FreeCAD.ActiveDocument
+ # filePath=last_pcb_path
+ # fpath=filePath+os.sep+doc.Label+'.kicad_pcb'
+ # sayerr('to '+fpath)
+
+ # print fname
+ fpath = original_filename if fname is None else fname
+
+ sayerr("saving to " + fpath)
+ # stop
+
if len(fpath) > 0:
- #new_edge_list=getBoardOutline()
- #say (new_edge_list)
+ # new_edge_list=getBoardOutline()
+ # say (new_edge_list)
cfg_read_all()
path, fname = os.path.split(fpath)
- name=os.path.splitext(fname)[0]
- ext=os.path.splitext(fname)[1]
+ name = os.path.splitext(fname)[0]
+ ext = os.path.splitext(fname)[1]
fpth = os.path.dirname(os.path.abspath(fpath))
- #filePath = os.path.split(os.path.realpath(__file__))[0]
- say ('my file path '+fpth)
+ # filePath = os.path.split(os.path.realpath(__file__))[0]
+ say("my file path " + fpth)
# stop
if fpth == "":
fpth = "."
last_pcb_path = fpth
last_pcb_path = re.sub("\\\\", "/", last_pcb_path)
ini_vars[10] = last_pcb_path
- #cfg_update_all()
+ # cfg_update_all()
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
pg.SetString("last_pcb_path", make_string(last_pcb_path))
- #sayerr(name+':'+ext)
- with codecs.open(fpath,'r', encoding='utf-8') as txtFile:
- content = txtFile.readlines() # problems?
- content.append(u" ")
+ # sayerr(name+':'+ext)
+ with codecs.open(fpath, "r", encoding="utf-8") as txtFile:
+ content = txtFile.readlines() # problems?
+ content.append(" ")
txtFile.close()
- data=u''.join(content)
- tml= time.localtime()
- now=str(tml.tm_year)+'-'+str(tml.tm_mon)+'-'+str(tml.tm_mday)+'-'+str(tml.tm_hour)+'.'+str(tml.tm_min)+'.'+str(tml.tm_sec)
- #foname=os.path.join(path, name+'-bkp-'+now+ext+'-bak')
- foname=os.path.join(path, name+u'-bkp-'+make_unicode(now)+ext+u'-bak')
- pcb_push=True
- testing=False
+ data = "".join(content)
+ tml = time.localtime()
+ now = (
+ str(tml.tm_year)
+ + "-"
+ + str(tml.tm_mon)
+ + "-"
+ + str(tml.tm_mday)
+ + "-"
+ + str(tml.tm_hour)
+ + "."
+ + str(tml.tm_min)
+ + "."
+ + str(tml.tm_sec)
+ )
+ # foname=os.path.join(path, name+'-bkp-'+now+ext+'-bak')
+ foname = os.path.join(path, name + "-bkp-" + make_unicode(now) + ext + "-bak")
+ pcb_push = True
+ testing = False
if testing is not True:
try:
- #with codecs.open(foname,'w', encoding='utf-8') as ofile:
+ # with codecs.open(foname,'w', encoding='utf-8') as ofile:
# ofile.write(data)
# ofile.close()
copyfile(fpath, foname)
- say('file copied')
+ say("file copied")
except:
- msg="""problem in writing permissions to kicad board!
"""
- msg+="file saving aborted to
"+fpath+"
"
- msgr="problem in writing permissions to kicad board!\n"
- msgr+="file saving aborted to "+fpath+"\n"
- pcb_push=False
+ msg = """problem in writing permissions to kicad board!
"""
+ msg += "file saving aborted to
" + fpath + "
"
+ msgr = "problem in writing permissions to kicad board!\n"
+ msgr += "file saving aborted to " + fpath + "\n"
+ pcb_push = False
say(msgr)
say_info(msg)
- if pcb_push==True:
+ if pcb_push:
if sklayer is None:
- ssklayer = 'Edge'
+ ssklayer = "Edge"
else:
say(sklayer)
- #ssklayer = sklayer.split('.')[0]
- skl = sklayer.split('.')[0]
- ln=len(sklayer.split('.'))
- if ln>1:
- skldot=sklayer.split('.')[1]
+ # ssklayer = sklayer.split('.')[0]
+ skl = sklayer.split(".")[0]
+ ln = len(sklayer.split("."))
+ if ln > 1:
+ skldot = sklayer.split(".")[1]
# say(skl)
# say(skldot)
try:
int(skldot)
ssklayer = sklayer
- #say('int ssk')
+ # say('int ssk')
except:
ssklayer = sklayer
else:
- ssklayer=skl
- #say(sklayer)
- #say(ssklayer)
- #stop
- if 'KeepOutZone' in sklayer:
- ssklayer = 'KeepOutZone'
- elif 'FillZone' in sklayer:
- ssklayer = 'FillZone'
- elif 'MaskZone' in sklayer:
- ssklayer = 'MaskZone'
+ ssklayer = skl
+ # say(sklayer)
+ # say(ssklayer)
+ # stop
+ if "KeepOutZone" in sklayer:
+ ssklayer = "KeepOutZone"
+ elif "FillZone" in sklayer:
+ ssklayer = "FillZone"
+ elif "MaskZone" in sklayer:
+ ssklayer = "MaskZone"
say(ssklayer)
- edge_pcb_exists=False
+ edge_pcb_exists = False
mypcb = KicadPCB.load(fpath)
pcb_version = mypcb.version
- sayw('parsing, pcb v='+str(pcb_version))
+ sayw("parsing, pcb v=" + str(pcb_version))
edg_segms = 0
for ln in mypcb.gr_line:
if ssklayer in ln.layer:
- #say(ln.layer)
- edg_segms+=1
+ # say(ln.layer)
+ edg_segms += 1
break
if edg_segms == 0:
for ar in mypcb.gr_arc:
if ssklayer in ar.layer:
- #say(ln.layer)
- edg_segms+=1
+ # say(ln.layer)
+ edg_segms += 1
break
if edg_segms == 0:
for cr in mypcb.gr_circle:
if ssklayer in cr.layer:
- #say(ln.layer)
- edg_segms+=1
+ # say(ln.layer)
+ edg_segms += 1
break
if edg_segms == 0:
for rr in mypcb.gr_rect:
if ssklayer in rr.layer:
- #say(ln.layer)
- edg_segms+=1
+ # say(ln.layer)
+ edg_segms += 1
break
if edg_segms == 0:
for lp in mypcb.gr_poly:
- #print(lp)
- #print(lp.layer)
- #print(lp.pts)
+ # print(lp)
+ # print(lp.layer)
+ # print(lp.pts)
if ssklayer in lp.layer:
- #sayerr(lp.layer)
+ # sayerr(lp.layer)
try:
for p in lp.pts.xy:
- edg_segms+=1
+ edg_segms += 1
break
- #sayerr(p)
+ # sayerr(p)
except:
for a in lp.pts.arc:
- edg_segms+=1
+ edg_segms += 1
break
- #stop
- #edg_segms+=1
+ # stop
+ # edg_segms+=1
if edg_segms == 0:
for bs in mypcb.gr_curve:
if ssklayer in bs.layer:
- #sayerr(bs.layer)
+ # sayerr(bs.layer)
for p in bs.pts.xy:
- edg_segms+=1
+ edg_segms += 1
break
- #edg_segms+=1
- #sayw(str(edg_segms)+' '+ssklayer+' segments')
- if (edg_segms)>0:
- edge_pcb_exists=True
- sayw('found '+ssklayer+' element(s)')
- #stop
- if ssklayer == 'Edge':
- if hasattr(mypcb, 'setup'):
- if hasattr(mypcb.setup, 'edge_width'): #maui edge width
- edge_width=mypcb.setup.edge_width
- elif hasattr(mypcb.setup, 'edge_cuts_line_width'): #maui edge cuts new width k 5.99
- edge_width=mypcb.setup.edge_cuts_line_width
- #else:
+ # edg_segms+=1
+ # sayw(str(edg_segms)+' '+ssklayer+' segments')
+ if (edg_segms) > 0:
+ edge_pcb_exists = True
+ sayw("found " + ssklayer + " element(s)")
+ # stop
+ if ssklayer == "Edge" and hasattr(mypcb, "setup"):
+ if hasattr(mypcb.setup, "edge_width"): # maui edge width
+ edge_width = mypcb.setup.edge_width
+ elif hasattr(mypcb.setup, "edge_cuts_line_width"): # maui edge cuts new width k 5.99
+ edge_width = mypcb.setup.edge_cuts_line_width
+ # else:
# edge_width=0.16
- oft=None
+ oft = None
origin_warn = False
- #skip = False
+ # skip = False
if aux_orig == 1:
- oft=getAuxOrigin(data)
+ oft = getAuxOrigin(data)
if oft is None:
- msg="""StepUp is configured for \'aux origin\' reference
but \'aux origin\' is not placed/set on kicad destination board"""
+ msg = """StepUp is configured for \'aux origin\' reference
but \'aux origin\' is not placed/set on kicad destination board"""
say_warning(msg)
stop
else:
- print ('aux_origin found',oft)
+ print("aux_origin found", oft)
elif grid_orig == 1:
- oft=getGridOrigin(data)
+ oft = getGridOrigin(data)
if oft is None:
- msg="""StepUp is configured for \'grid origin\' reference
but \'grid origin\' is not placed/set on kicad destination board"""
+ msg = """StepUp is configured for \'grid origin\' reference
but \'grid origin\' is not placed/set on kicad destination board"""
say_warning(msg)
stop
else:
- if oft == [0.0,0.0]:
+ if oft == [0.0, 0.0]:
origin_warn = True
- print ('grid_origin found',oft)
+ print("grid_origin found", oft)
else:
- print('using an approximate PCB center as sketch reference point')
- #print oft
- gof=False
+ print("using an approximate PCB center as sketch reference point")
+ # print oft
+ gof = False
if oft is not None:
- off_x=oft[0];off_y=-oft[1]
+ off_x = oft[0]
+ off_y = -oft[1]
offset = oft
- gof=True
-
- if edge_pcb_exists and ssklayer != 'FillZone' and ssklayer != 'KeepOutZone':
- #offset=[0,0]
- doc=FreeCAD.ActiveDocument
- ksu_found=False;skt_name='';pcb_found=False
+ gof = True
+
+ if edge_pcb_exists and ssklayer not in {"FillZone", "KeepOutZone"}:
+ # offset=[0,0]
+ doc = FreeCAD.ActiveDocument
+ ksu_found = False
+ skt_name = ""
+ pcb_found = False
for obj in doc.Objects:
- if ("PCB_Sketch" in obj.Name) or ("PCB_Sketch" in obj.Label) or\
- ("Edge_Sketch" in obj.Name) or ("Edge.Cuts" in obj.Label) or \
- ("Dwgs_Sketch" in obj.Name) or ("Dwgs.User" in obj.Label) or \
- ("Eco1_Sketch" in obj.Name) or ("Eco1.User" in obj.Label) or \
- ("Eco2_Sketch" in obj.Name) or ("Eco2.User" in obj.Label) or \
- ("Cmts_Sketch" in obj.Name) or ("Cmts.User" in obj.Label) or \
- ("Margin_Sketch" in obj.Name) or ("Margin" in obj.Label) or ("User." in obj.Label):
- ksu_found=True
- skt_name=obj.Name
- if ("Pcb" in obj.Name):
- ksu_found=True
- pcb_found=True
- testing=False
+ if (
+ ("PCB_Sketch" in obj.Name)
+ or ("PCB_Sketch" in obj.Label)
+ or ("Edge_Sketch" in obj.Name)
+ or ("Edge.Cuts" in obj.Label)
+ or ("Dwgs_Sketch" in obj.Name)
+ or ("Dwgs.User" in obj.Label)
+ or ("Eco1_Sketch" in obj.Name)
+ or ("Eco1.User" in obj.Label)
+ or ("Eco2_Sketch" in obj.Name)
+ or ("Eco2.User" in obj.Label)
+ or ("Cmts_Sketch" in obj.Name)
+ or ("Cmts.User" in obj.Label)
+ or ("Margin_Sketch" in obj.Name)
+ or ("Margin" in obj.Label)
+ or ("User." in obj.Label)
+ ):
+ ksu_found = True
+ skt_name = obj.Name
+ if "Pcb" in obj.Name:
+ ksu_found = True
+ pcb_found = True
+ testing = False
if testing is True:
- off_x=0;off_y=0
- if ksu_found==True or testing==True or ssklayer != 'Edge':
- if pcb_found==True:
- #FreeCAD.ActiveDocument.getObject(skname).recompute(True)
- #bbpx=-FreeCAD.ActiveDocument.getObject('Pcb').Placement.Base[0]+FreeCAD.ActiveDocument.getObject(skt_name).Placement.Base[0]
- #bbpy=FreeCAD.ActiveDocument.getObject('Pcb').Placement.Base[1]-FreeCAD.ActiveDocument.getObject(skt_name).Placement.Base[1]
- bbpx=-FreeCAD.ActiveDocument.getObject(skname).Placement.Base[0]+FreeCAD.ActiveDocument.getObject(skt_name).Placement.Base[0]
- bbpy=FreeCAD.ActiveDocument.getObject(skname).Placement.Base[1]-FreeCAD.ActiveDocument.getObject(skt_name).Placement.Base[1]
- offset=[bbpx,bbpy]
+ off_x = 0
+ off_y = 0
+ if ksu_found or testing or ssklayer != "Edge":
+ if pcb_found:
+ # FreeCAD.ActiveDocument.getObject(skname).recompute(True)
+ # bbpx=-FreeCAD.ActiveDocument.getObject('Pcb').Placement.Base[0]+FreeCAD.ActiveDocument.getObject(skt_name).Placement.Base[0]
+ # bbpy=FreeCAD.ActiveDocument.getObject('Pcb').Placement.Base[1]-FreeCAD.ActiveDocument.getObject(skt_name).Placement.Base[1]
+ bbpx = (
+ -FreeCAD.ActiveDocument.getObject(skname).Placement.Base[0]
+ + FreeCAD.ActiveDocument.getObject(skt_name).Placement.Base[0]
+ )
+ bbpy = (
+ FreeCAD.ActiveDocument.getObject(skname).Placement.Base[1]
+ - FreeCAD.ActiveDocument.getObject(skt_name).Placement.Base[1]
+ )
+ offset = [bbpx, bbpy]
else:
- off_x=0;off_y=0
- offset=[off_x,-off_y]
- if gof and grid_orig==1:
- offset=[off_x,-off_y]
- offset = (getGridOrigin(data)[0],getGridOrigin(data)[1])
- elif gof and aux_orig==1:
- offset=[off_x,-off_y]
- offset = (getAuxOrigin(data)[0],getAuxOrigin(data)[1])
- #if gof and not pcb_found:
+ off_x = 0
+ off_y = 0
+ offset = [off_x, -off_y]
+ if gof and grid_orig == 1:
+ offset = [off_x, -off_y]
+ offset = (getGridOrigin(data)[0], getGridOrigin(data)[1])
+ elif gof and aux_orig == 1:
+ offset = [off_x, -off_y]
+ offset = (getAuxOrigin(data)[0], getAuxOrigin(data)[1])
+ # if gof and not pcb_found:
# offset=[0,0]
## maui to test position
- #print offset
- #say(offset)
- #stop
- if ssklayer == 'Edge':
- say('pcb edge exists')
- sayw('removing old pcb '+ssklayer)
+ # print offset
+ # say(offset)
+ # stop
+ if ssklayer == "Edge":
+ say("pcb edge exists")
+ sayw("removing old pcb " + ssklayer)
else:
- sayw('removing existing drawings '+ssklayer)
+ sayw("removing existing drawings " + ssklayer)
## removing old Edge w/ better parsing kv8 compat
- clr_content = u""
- l = len (content)
+ clr_content = ""
+ l = len(content)
id = 0
- #offset_id=id+1
+ # offset_id=id+1
add_line = True
- #line = content[id]
+ # line = content[id]
while id < l:
line = content[id]
- #print (line,id)
+ # print (line,id)
# kv8 Check if given Parentheses expression is balanced
## checking if gr_something is inside a footprint https://gitlab.com/kicad/code/kicad/-/issues/16660
## idr = searchInsideFootprint (content, id)
@@ -21373,49 +23291,60 @@ def export_pcb(fname=None,sklayer=None,skname=None):
## # stop
## id = idr
## line = content[id]
- if '(gr_line' in line or '(gr_curve' in line or '(gr_arc' in line or '(gr_circle' in line or '(gr_rect' in line or '(gr_poly' in line:
- #print ('inside', line,id)
- add_line,delta = search_content(content,id,ssklayer)
+ if (
+ "(gr_line" in line
+ or "(gr_curve" in line
+ or "(gr_arc" in line
+ or "(gr_circle" in line
+ or "(gr_rect" in line
+ or "(gr_poly" in line
+ ):
+ # print ('inside', line,id)
+ add_line, delta = search_content(content, id, ssklayer)
# offset=id+1 ## tmp to test
- if add_line == True:
- #if offset-id == 1:
+ if add_line:
+ # if offset-id == 1:
clr_content += content[id]
- id+=1
- #print('line added')
+ id += 1
+ # print('line added')
else:
- #print(line,'line NOT added',delta)
- cnt=id
- while cntto push a new release of Edge to a kicad board
with an existing Edge
you need to load the board with StepUp first
""")
+ sayerr(
+ "to push a new release of Edge to a kicad board with an existing Edge\nyou need to load the board with StepUp first",
+ )
+ say_error(
+ """to push a new release of Edge to a kicad board
with an existing Edge
you need to load the board with StepUp first
""",
+ )
stop
else:
- #[148.5, -98.5] center of A4 page
- if gof and grid_orig==1:
- sayw('pcb edge does not exist, aligning sketch to Grid Origin')
- offset=[off_x,-off_y]
- elif gof and aux_orig==1:
- sayw('pcb edge does not exist, aligning sketch to Aux Origin')
- offset=[off_x,-off_y]
+ # [148.5, -98.5] center of A4 page
+ if gof and grid_orig == 1:
+ sayw("pcb edge does not exist, aligning sketch to Grid Origin")
+ offset = [off_x, -off_y]
+ elif gof and aux_orig == 1:
+ sayw("pcb edge does not exist, aligning sketch to Aux Origin")
+ offset = [off_x, -off_y]
else:
- sayw('pcb edge does not exist, aligning sketch to center of A4 page')
- offset=[148.5,98.5]
+ sayw("pcb edge does not exist, aligning sketch to center of A4 page")
+ offset = [148.5, 98.5]
##sel = FreeCADGui.Selection.getSelection()
##if len (sel) >0:
## #sayw(doc.Name)
@@ -21424,220 +23353,232 @@ def export_pcb(fname=None,sklayer=None,skname=None):
## #FreeCAD.ActiveDocument.getObject(j.Name).Placement = FreeCAD.Placement(FreeCAD.Vector(148.5, -98.5,0),FreeCAD.Rotation(FreeCAD.Vector(0,0,1),0))
## if FreeCAD.ActiveDocument.getObject(j.Name).Placement.Base[0]==0: #sketch created at FC origin
## FreeCAD.ActiveDocument.getObject(j.Name).Placement = FreeCAD.Placement(FreeCAD.Vector(148.5,-98.5,0), App.Rotation(0,0,0), App.Vector(0,0,0)) #[Pos=(-148.5,98,5), Yaw-Pitch-Roll=(0,0,0)]
-
- #shift_sketch(j.Name,offset)
- #sel = FreeCADGui.Selection.getSelection()
- #if len (sel) >0:
+
+ # shift_sketch(j.Name,offset)
+ # sel = FreeCADGui.Selection.getSelection()
+ # if len (sel) >0:
# sel[0].recompute(True)
FreeCAD.ActiveDocument.recompute()
- if (zfit):
+ if zfit:
FreeCADGui.SendMsgToActiveView("ViewFit")
- k = data.rfind(")") #removing latest ')'
- newcontent = data[:k]
-
- to_discretize = []; not_supported = []
- if ssklayer != 'FillZone' and ssklayer != 'MaskZone' and ssklayer != 'KeepOutZone':
- new_edge_list, not_supported, to_discretize, construction_geom = getBoardOutline()
- #print (new_edge_list)
- #stop
-
- #geoL=len(App.ActiveDocument.getObject("PCB_Sketch").Geometry)
- if len(to_discretize)>0:
- #stop
+ k = data.rfind(")") # removing latest ')'
+ newcontent = data[:k]
+
+ to_discretize = []
+ not_supported = []
+ if ssklayer not in {"FillZone", "MaskZone", "KeepOutZone"}:
+ new_edge_list, not_supported, to_discretize, _construction_geom = getBoardOutline()
+ # print (new_edge_list)
+ # stop
+
+ # geoL=len(App.ActiveDocument.getObject("PCB_Sketch").Geometry)
+ if len(to_discretize) > 0:
+ # stop
sel = FreeCADGui.Selection.getSelection()
- if len (sel)==1:
- sk_name=sel[0].Name
- t_name=cpy_sketch(sk_name)
+ if len(sel) == 1:
+ sk_name = sel[0].Name
+ t_name = cpy_sketch(sk_name)
###t_sk=FreeCAD.ActiveDocument.copyObject(FreeCAD.ActiveDocument.getObject(sk_name))
- elist, to_dis=check_geom(t_name)
- #Draft.clone(FreeCAD.ActiveDocument.getObject(sk_name),copy=True)
- #clone_name=App.ActiveDocument.ActiveObject.Name
+ elist, to_dis = check_geom(t_name)
+ # Draft.clone(FreeCAD.ActiveDocument.getObject(sk_name),copy=True)
+ # clone_name=App.ActiveDocument.ActiveObject.Name
remove_basic_geom(t_name, to_dis)
##remove_basic_geom(t_sk.Name, to_discretize)
##elist, to_dis=check_geom(t_sk.Name)
- #print elist
- #stop
- obj_list_prev=[]
+ # print elist
+ # stop
+ obj_list_prev = []
for obj in doc.Objects:
- #print obj.TypeId
- if (obj.TypeId=="Part::Feature") or (obj.TypeId=="Sketcher::SketchObject"):
+ # print obj.TypeId
+ if obj.TypeId in {"Part::Feature", "Sketcher::SketchObject"}:
obj_list_prev.append(obj.Name)
- #Draft.draftify(FreeCAD.ActiveDocument.getObject(t_name),delete=True)
- #Draft.draftify(FreeCAD.ActiveDocument.getObject(t_name),delete=False)
- b=FreeCAD.ActiveDocument.getObject(t_name)
- shp1=b.Shape.copy()
+ # Draft.draftify(FreeCAD.ActiveDocument.getObject(t_name),delete=True)
+ # Draft.draftify(FreeCAD.ActiveDocument.getObject(t_name),delete=False)
+ b = FreeCAD.ActiveDocument.getObject(t_name)
+ shp1 = b.Shape.copy()
Part.show(shp1)
FreeCAD.ActiveDocument.removeObject(t_name)
FreeCAD.ActiveDocument.recompute()
- #stop
- obj_list_after=[]
+ # stop
+ obj_list_after = []
for obj in doc.Objects:
- if (obj.TypeId=="Part::Feature") or (obj.TypeId=="Sketcher::SketchObject")\
- or (obj.TypeId=="Part::Part2DObjectPython"):
- if obj.Name not in obj_list_prev:
- obj_list_after.append(obj.Name)
- #print obj_list_after #, obj_list_prev
- sk_to_conv=[]
+ if obj.TypeId in {"Part::Feature", "Sketcher::SketchObject", "Part::Part2DObjectPython"}:
+ if obj.Name not in obj_list_prev:
+ obj_list_after.append(obj.Name)
+ # print obj_list_after #, obj_list_prev
+ sk_to_conv = []
for obj in doc.Objects:
if obj.Name in obj_list_after:
- if (obj.TypeId=="Part::Part2DObjectPython"):
+ if obj.TypeId == "Part::Part2DObjectPython":
FreeCAD.ActiveDocument.removeObject(obj.Name)
- FreeCAD.ActiveDocument.recompute()
+ FreeCAD.ActiveDocument.recompute()
else:
sk_to_conv.append(obj.Name)
- keep_sketch_converted=False #False
+ keep_sketch_converted = False # False
for s in sk_to_conv:
- #sayerr(s) ##
- ns=Discretize(s)
- offset1=[-FreeCAD.ActiveDocument.getObject(sk_name).Placement.Base[0],-FreeCAD.ActiveDocument.getObject(sk_name).Placement.Base[1]]
- elist, to_dis=check_geom(ns,offset1)
- new_edge_list=new_edge_list+elist
+ # sayerr(s) ##
+ ns = Discretize(s)
+ offset1 = [
+ -FreeCAD.ActiveDocument.getObject(sk_name).Placement.Base[0],
+ -FreeCAD.ActiveDocument.getObject(sk_name).Placement.Base[1],
+ ]
+ elist, to_dis = check_geom(ns, offset1)
+ new_edge_list = new_edge_list + elist
if not keep_sketch_converted:
FreeCAD.ActiveDocument.removeObject(ns)
FreeCAD.ActiveDocument.recompute()
- #print new_edge_list
- #stop
- #if len (not_supported)>0:
+ # print new_edge_list
+ # stop
+ # if len (not_supported)>0:
# Draft.downgrade(FreeCADGui.Selection.getSelection(),delete=False)
# stop
- #say (new_edge_list)
- #stop
- #sayerr(replace)
- #replace = re.sub('\s\(gr_arc(.+?Edge)\)\)\r\n|\(gr_line(.+?Edge)\)\)\r|\(gr_line(.+?Edge)\)\)\n','',replace, flags=re.MULTILINE)
- #replace = re.sub('\s\(gr_circle(.+?Edge)\)\)\r\n|\(gr_line(.+?Edge)\)\)\r|\(gr_line(.+?Edge)\)\)\n','',replace, flags=re.MULTILINE)
- #newcontent = re.sub('^\)','ENDOFFILE',replace, flags=re.MULTILINE)
-
- #newcontent = re.sub('^\)','',replace, flags=re.MULTILINE) #end of file
- #newcontent = re.sub('/\.(?=[^\(]*$)/','',replace, flags=re.MULTILINE) #end of file
- #newcontent = newcontent.replace(/\((?=[^.]*$)/, "")
- #newcontent = re.sub(r'(.*)\)', r'', replace, flags=re.MULTILINE)
- new_border=''
- #print new_edge_list
+ # say (new_edge_list)
+ # stop
+ # sayerr(replace)
+ # replace = re.sub('\s\(gr_arc(.+?Edge)\)\)\r\n|\(gr_line(.+?Edge)\)\)\r|\(gr_line(.+?Edge)\)\)\n','',replace, flags=re.MULTILINE)
+ # replace = re.sub('\s\(gr_circle(.+?Edge)\)\)\r\n|\(gr_line(.+?Edge)\)\)\r|\(gr_line(.+?Edge)\)\)\n','',replace, flags=re.MULTILINE)
+ # newcontent = re.sub('^\)','ENDOFFILE',replace, flags=re.MULTILINE)
+
+ # newcontent = re.sub('^\)','',replace, flags=re.MULTILINE) #end of file
+ # newcontent = re.sub('/\.(?=[^\(]*$)/','',replace, flags=re.MULTILINE) #end of file
+ # newcontent = newcontent.replace(/\((?=[^.]*$)/, "")
+ # newcontent = re.sub(r'(.*)\)', r'', replace, flags=re.MULTILINE)
+ new_border = ""
+ # print new_edge_list
## maxRadius # 4000 = 4m max length for KiCad
- #edge_nbr=0
- sanitized_edge_list=[]
+ # edge_nbr=0
+ sanitized_edge_list = []
for border in new_edge_list:
- #print (border) # [0]
- if 'arc' in border[0]:
- #print border[0]
+ # print (border) # [0]
+ if "arc" in border[0]:
+ # print border[0]
if abs(float(border[3])) > maxRadius:
- #stop
- #print 'too big radius= ',border[3]
- #print 'border len= ', len(border)
- #points=border [10].x
- #p1x = float(border [10].x);p1y=float(border [10].y)
- p1x = float("{0:.6f}".format(border [10].x));p1y=float("{0:.6f}".format(border [10].y))
- #print p1x, ' ',p1y
- #p2x = float(border [11].x);p2y=float(border [11].y)
- p2x = float("{0:.6f}".format(border [11].x));p2y=float("{0:.6f}".format(border [11].y))
- #print '1st point ', border [10],' 2nd point ', border [11]
- sanitized_edge_list.append(['line',p1x,p1y,p2x,p2y])
+ # stop
+ # print 'too big radius= ',border[3]
+ # print 'border len= ', len(border)
+ # points=border [10].x
+ # p1x = float(border [10].x);p1y=float(border [10].y)
+ p1x = float(f"{border[10].x:.6f}")
+ p1y = float(f"{border[10].y:.6f}")
+ # print p1x, ' ',p1y
+ # p2x = float(border [11].x);p2y=float(border [11].y)
+ p2x = float(f"{border[11].x:.6f}")
+ p2y = float(f"{border[11].y:.6f}")
+ # print '1st point ', border [10],' 2nd point ', border [11]
+ sanitized_edge_list.append(["line", p1x, p1y, p2x, p2y])
else:
sanitized_edge_list.append(border)
else:
sanitized_edge_list.append(border)
- #edge_nbr=edge_nbr+1
- #print sanitized_edge_list
- #stop
- #for border in new_edge_list:
+ # edge_nbr=edge_nbr+1
+ # print sanitized_edge_list
+ # stop
+ # for border in new_edge_list:
for border in sanitized_edge_list:
- new_border=new_border+os.linesep+createEdge(border,offset,sklayer,pcb_version)
- #sayw(createEdge(border))
- #stop
- new_edge=new_border+os.linesep+')'+os.linesep
+ new_border = new_border + os.linesep + createEdge(border, offset, sklayer, pcb_version)
+ # sayw(createEdge(border))
+ # stop
+ new_edge = new_border + os.linesep + ")" + os.linesep
# print(new_edge)
- newcontent=newcontent+new_edge+u' '
- elif ssklayer == 'FillZone' or ssklayer == 'MaskZone':
- newcontent=newcontent+pushFillZone(skname,offset,sklayer)+os.linesep+')'+os.linesep+u' '
+ newcontent = newcontent + new_edge + " "
+ elif ssklayer in {"FillZone", "MaskZone"}:
+ newcontent = newcontent + pushFillZone(skname, offset, sklayer) + os.linesep + ")" + os.linesep + " "
else:
- newcontent=newcontent+pushFillZone(skname,offset,sklayer)+os.linesep+')'+os.linesep+u' '
- #print newcontent
- with codecs.open(fpath,'w', encoding='utf-8') as ofile:
+ newcontent = newcontent + pushFillZone(skname, offset, sklayer) + os.linesep + ")" + os.linesep + " "
+ # print newcontent
+ with codecs.open(fpath, "w", encoding="utf-8") as ofile:
ofile.write(newcontent)
- ofile.close()
+ ofile.close()
say_time()
- if ssklayer != 'FillZone' and ssklayer != 'MaskZone' and ssklayer != 'KeepOutZone':
- msg="""new Edge pushed to kicad board!
"""
- elif ssklayer == 'FillZone':
- msg="""new FillZone pushed to kicad board!
Edit the properties of the new FillZone in pcbnew
"""
- elif ssklayer == 'MaskZone':
- msg="""new MaskZone pushed to kicad board!
Edit the properties of the new FillZone in pcbnew
"""
- elif ssklayer == 'KeepOutZone':
- msg="""new KeepOutZone pushed to kicad board!
Edit the properties of the new KeepOutZone in pcbnew
"""
- msg+="file saved to
"+fpath+"
"
- msg+="backup file saved to
"+foname+"
"
- if ssklayer == 'Edge':
- msgr="new Edge pushed to kicad board!\n"
+ if ssklayer not in {"FillZone", "MaskZone", "KeepOutZone"}:
+ msg = """new Edge pushed to kicad board!
"""
+ elif ssklayer == "FillZone":
+ msg = """new FillZone pushed to kicad board!
Edit the properties of the new FillZone in pcbnew
"""
+ elif ssklayer == "MaskZone":
+ msg = """new MaskZone pushed to kicad board!
Edit the properties of the new FillZone in pcbnew
"""
+ elif ssklayer == "KeepOutZone":
+ msg = """new KeepOutZone pushed to kicad board!
Edit the properties of the new KeepOutZone in pcbnew
"""
+ msg += "file saved to
" + fpath + "
"
+ msg += "backup file saved to
" + foname + "
"
+ if ssklayer == "Edge":
+ msgr = "new Edge pushed to kicad board!\n"
else:
- msgr="new "+ssklayer+" pushed to kicad board!\n"
- msgr+="file saved to "+fpath+"\n"
- msgr+="backup file saved to "+foname
- lns=len (not_supported)
- #print lns
+ msgr = "new " + ssklayer + " pushed to kicad board!\n"
+ msgr += "file saved to " + fpath + "\n"
+ msgr += "backup file saved to " + foname
+ lns = len(not_supported)
+ # print lns
if lns > 2:
- if lns < 103: # writing only some geometry not supported
- msg+="
found downgraded Geometry:
"+not_supported[:-2]+"!"
- msgr+="\nfound downgraded Geometry: "+not_supported[:-2]+"!"
+ if lns < 103: # writing only some geometry not supported
+ msg += "
found downgraded Geometry:
" + not_supported[:-2] + "!"
+ msgr += "\nfound downgraded Geometry: " + not_supported[:-2] + "!"
else:
- nss=not_supported[:-2]
- nss=nss[:101]+'...
...'
- msg+="
found downgraded Geometry:
"+nss+""
- msgr+="\nfound downgraded Geometry: "+not_supported[:-2]+"!"
-
+ nss = not_supported[:-2]
+ nss = nss[:101] + "...
..."
+ msg += "
found downgraded Geometry:
" + nss + ""
+ msgr += "\nfound downgraded Geometry: " + not_supported[:-2] + "!"
+
say(msgr)
say_info(msg)
- if not edge_pcb_exists and ssklayer != 'FillZone' and ssklayer != 'KeepOutZone':
- msg="close your FC Sketch
and reload the kicad_pcb file"
+ if not edge_pcb_exists and ssklayer not in {"FillZone", "KeepOutZone"}:
+ msg = "close your FC Sketch
and reload the kicad_pcb file"
say_warning(msg)
if origin_warn:
if aux_orig == 1:
- origin_msg='AuxOrigin'
+ origin_msg = "AuxOrigin"
elif grid_orig == 1:
- origin_msg='GridOrigin'
- msg = origin_msg +' is set in FC Preferences but not set in KiCAD pcbnew file'
+ origin_msg = "GridOrigin"
+ msg = origin_msg + " is set in FC Preferences but not set in KiCAD pcbnew file"
sayw(msg)
- msg=""""""+origin_msg+""" is set in FreeCAD Preferences
but not set in KiCAD pcbnew file"""
- msg+="""
Please assign """+origin_msg+""" to your KiCAD pcbnew board file"""
- msg+="""
for a better Mechanical integration"""
+ msg = (
+ """"""
+ + origin_msg
+ + """ is set in FreeCAD Preferences
but not set in KiCAD pcbnew file"""
+ )
+ msg += """
Please assign """ + origin_msg + """ to your KiCAD pcbnew board file"""
+ msg += """
for a better Mechanical integration"""
say_warning(msg)
- #def precision(self, value):
+ # def precision(self, value):
# return "%.2f" % float(value)
-
+
+
##
-def find_sequence (elist,idx, min_dist):
+def find_sequence(elist, idx, min_dist):
"""find point sequence in two edges"""
ep0 = elist[idx].Vertexes[0].Point
ep1 = elist[idx].Vertexes[1].Point
- ep2 = elist[idx+1].Vertexes[0].Point
- ep3 = elist[idx+1].Vertexes[1].Point
- if distance(ep0,ep2) < min_dist:
+ ep2 = elist[idx + 1].Vertexes[0].Point
+ ep3 = elist[idx + 1].Vertexes[1].Point
+ if distance(ep0, ep2) < min_dist:
first_pnt = ep1
common_pnt = ep0
last_pnt = ep3
- elif distance(ep0,ep3) < min_dist:
+ elif distance(ep0, ep3) < min_dist:
first_pnt = ep1
common_pnt = ep3
last_pnt = ep2
- elif distance(ep1,ep3) < min_dist:
+ elif distance(ep1, ep3) < min_dist:
first_pnt = ep0
common_pnt = ep1
last_pnt = ep2
- elif distance(ep1,ep2) < min_dist:
+ elif distance(ep1, ep2) < min_dist:
first_pnt = ep0
common_pnt = ep1
last_pnt = ep3
else:
- msg="""to push a FillZone or a KeepOutZone
you need a single closed Sketch!"""
+ msg = """to push a FillZone or a KeepOutZone
you need a single closed Sketch!"""
say_warning(msg)
stop
return first_pnt, common_pnt, last_pnt
+
+
##
def pushFillZone(skn, ofs, keepout=None):
shapes = []
- q_deflection = 0.005 #0.02 ##0.005
+ q_deflection = 0.005 # 0.02 ##0.005
tol = 0.01
- constr = 'coincident' #'all'
+ constr = "coincident" #'all'
if skn is None:
sel = FreeCADGui.Selection.getSelection()
for selobj in sel:
@@ -21650,502 +23591,655 @@ def pushFillZone(skn, ofs, keepout=None):
Draft.makeSketch(shapes)
sk_d = FreeCAD.ActiveDocument.ActiveObject
if sk_d is not None:
- FreeCADGui.ActiveDocument.getObject(sk_d.Name).LineColor = (1.00,1.00,1.00)
- FreeCADGui.ActiveDocument.getObject(sk_d.Name).PointColor = (1.00,1.00,1.00)
- max_geo_admitted = 1500 # after this number, no recompute is applied
- if len (sk_d.Geometry) < max_geo_admitted:
+ FreeCADGui.ActiveDocument.getObject(sk_d.Name).LineColor = (1.00, 1.00, 1.00)
+ FreeCADGui.ActiveDocument.getObject(sk_d.Name).PointColor = (1.00, 1.00, 1.00)
+ max_geo_admitted = 1500 # after this number, no recompute is applied
+ if len(sk_d.Geometry) < max_geo_admitted:
FreeCAD.ActiveDocument.recompute()
import constrainator
+
constrainator.add_constraints(sk_d.Name, tol, constr)
skt = FreeCAD.ActiveDocument.getObject(sk_d.Name)
- if hasattr(skt, 'OpenVertices'):
+ if hasattr(skt, "OpenVertices"):
openVtxs = skt.OpenVertices
- if len(openVtxs) >0:
+ if len(openVtxs) > 0:
FreeCAD.Console.PrintError("Open Vertexes found.\n")
- FreeCAD.Console.PrintWarning(str(openVtxs)+'\n')
- msg = """Open Vertexes found.
"""+str(openVtxs)
- reply = QtGui.QMessageBox.information(None,"info", msg)
- add_points=True
+ FreeCAD.Console.PrintWarning(str(openVtxs) + "\n")
+ msg = """Open Vertexes found.
""" + str(openVtxs)
+ QtGui.QMessageBox.information(None, "info", msg)
+ add_points = True
if add_points:
for v in openVtxs:
- FreeCAD.ActiveDocument.addObject('PartDesign::Point','DatumPoint')
+ FreeCAD.ActiveDocument.addObject("PartDesign::Point", "DatumPoint")
dp = FreeCAD.ActiveDocument.ActiveObject
- dp.Placement = FreeCAD.Placement (FreeCAD.Vector(v[0],v[1],0), FreeCAD.Rotation(0,0,0), FreeCAD.Vector(0,0,0))
- dp.Label = 'OpenVertexPointer'
- #FreeCADGui.ActiveDocument.getObject(sel[0].Name).Visibility=False
+ dp.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(v[0], v[1], 0),
+ FreeCAD.Rotation(0, 0, 0),
+ FreeCAD.Vector(0, 0, 0),
+ )
+ dp.Label = "OpenVertexPointer"
+ # FreeCADGui.ActiveDocument.getObject(sel[0].Name).Visibility=False
shp = skt.Shape
- #ofs=[0.0,0.0]
- edge_width = 0.1
+ # ofs=[0.0,0.0]
edges = shp.Edges
- segments_nbr=len(edges)
- if segments_nbr<3:
+ segments_nbr = len(edges)
+ if segments_nbr < 3:
stop
- if 'Fill' in keepout:
- fillzone = """ (zone (net 0) (net_name "") (layer """+keepout[:1]+""".Cu) (tstamp 0) (hatch edge 0.508)"""+os.linesep
- fillzone+=""" (connect_pads (clearance 0.508))"""+os.linesep
- fillzone+=""" (min_thickness 0.254)"""+os.linesep
- fillzone+=""" (fill yes (arc_segments 32) (thermal_gap 0.508) (thermal_bridge_width 0.508))"""+os.linesep
- fillzone+=""" (polygon"""+os.linesep
- elif 'Mask' in keepout:
- fillzone = """ (gr_poly"""+os.linesep
- elif 'KeepOut' in keepout: #keepout zone
- fillzone = """ (zone (net 0) (net_name "") (layers """+keepout[:1]+""".Cu) (tstamp 0) (hatch edge 0.508)"""+os.linesep
- fillzone+=""" (connect_pads (clearance 0.508))"""+os.linesep
- fillzone+=""" (min_thickness 0.254)"""+os.linesep
- fillzone+=""" (keepout (tracks not_allowed) (vias not_allowed) (copperpour not_allowed))"""+os.linesep
- fillzone+=""" (fill (arc_segments 32) (thermal_gap 0.508) (thermal_bridge_width 0.508))"""+os.linesep
- fillzone+=""" (polygon"""+os.linesep
- i=0
- pts = " (pts "+os.linesep
- first_pnt, common_pnt, last_pnt = find_sequence (edges,i,tol)
- i+=1
+ if "Fill" in keepout:
+ fillzone = (
+ """ (zone (net 0) (net_name "") (layer """
+ + keepout[:1]
+ + """.Cu) (tstamp 0) (hatch edge 0.508)"""
+ + os.linesep
+ )
+ fillzone += """ (connect_pads (clearance 0.508))""" + os.linesep
+ fillzone += """ (min_thickness 0.254)""" + os.linesep
+ fillzone += """ (fill yes (arc_segments 32) (thermal_gap 0.508) (thermal_bridge_width 0.508))""" + os.linesep
+ fillzone += """ (polygon""" + os.linesep
+ elif "Mask" in keepout:
+ fillzone = """ (gr_poly""" + os.linesep
+ elif "KeepOut" in keepout: # keepout zone
+ fillzone = (
+ """ (zone (net 0) (net_name "") (layers """
+ + keepout[:1]
+ + """.Cu) (tstamp 0) (hatch edge 0.508)"""
+ + os.linesep
+ )
+ fillzone += """ (connect_pads (clearance 0.508))""" + os.linesep
+ fillzone += """ (min_thickness 0.254)""" + os.linesep
+ fillzone += """ (keepout (tracks not_allowed) (vias not_allowed) (copperpour not_allowed))""" + os.linesep
+ fillzone += """ (fill (arc_segments 32) (thermal_gap 0.508) (thermal_bridge_width 0.508))""" + os.linesep
+ fillzone += """ (polygon""" + os.linesep
+ i = 0
+ pts = " (pts " + os.linesep
+ first_pnt, common_pnt, last_pnt = find_sequence(edges, i, tol)
+ i += 1
for e in edges[1:-1]:
- if 'Line' not in str(e.Curve):
+ if "Line" not in str(e.Curve):
stop
- first_pnt, common_pnt, last_pnt = find_sequence (edges,i,tol)
+ first_pnt, common_pnt, last_pnt = find_sequence(edges, i, tol)
if i < segments_nbr:
- pts=pts+" (xy {0:.3f} {1:.3f}) (xy {2:.3f} {3:.3f})".format(first_pnt.x+ofs[0], -first_pnt.y+ofs[1], common_pnt.x+ofs[0], -common_pnt.y+ofs[1])+os.linesep
- i=i+1
- pts=pts+" (xy {0:.3f} {1:.3f})".format(last_pnt.x+ofs[0], -last_pnt.y+ofs[1])+os.linesep
+ pts = (
+ pts
+ + f" (xy {first_pnt.x + ofs[0]:.3f} {-first_pnt.y + ofs[1]:.3f}) (xy {common_pnt.x + ofs[0]:.3f} {-common_pnt.y + ofs[1]:.3f})"
+ + os.linesep
+ )
+ i = i + 1
+ pts = pts + f" (xy {last_pnt.x + ofs[0]:.3f} {-last_pnt.y + ofs[1]:.3f})" + os.linesep
fillzone += pts
- if 'Mask' in keepout:
- fillzone+=" )"+os.linesep+" (layer "+keepout[:6]+") (width 0.0))"+os.linesep
+ if "Mask" in keepout:
+ fillzone += " )" + os.linesep + " (layer " + keepout[:6] + ") (width 0.0))" + os.linesep
else:
- fillzone+=" )"+os.linesep+" )"+os.linesep+" )"+os.linesep #+")"+os.linesep
+ fillzone += " )" + os.linesep + " )" + os.linesep + " )" + os.linesep # +")"+os.linesep
if sk_d is not None:
FreeCAD.ActiveDocument.removeObject(sk_d.Name)
- #print(fillzone)
- #FreeCAD.ActiveDocument.commitTransaction()
- #with open(filename, "wb") as f:
+ # print(fillzone)
+ # FreeCAD.ActiveDocument.commitTransaction()
+ # with open(filename, "wb") as f:
# f.write(fillzone.encode('utf-8'))
return fillzone
+
+
##
-def pull3D2dsn(s,mdls,tsp,nMd,gof,pcbThickness):
+def pull3D2dsn(s, mdls, tsp, nMd, gof, pcbThickness):
global start_time, aux_orig, grid_orig
global board_base_point_x, board_base_point_y, real_board_pos_x, real_board_pos_y
global off_x, off_y, maxRadius
-
- #sayw('pulling 3D model placement from pcb')
- doc=FreeCAD.ActiveDocument
- if gof and grid_orig==1:
- offset=[off_x,-off_y]
- #print(offset)
+
+ # sayw('pulling 3D model placement from pcb')
+ if gof and grid_orig == 1:
+ pass
+ # print(offset)
if 0:
- model_3d_name = s.Label[s.Label.find('_')+1:s.Label.rfind('_')]
- model_3d_name = model_3d_name.replace('.','')
- #print (model_3d_name);stop
+ model_3d_name = s.Label[s.Label.find("_") + 1 : s.Label.rfind("_")]
+ model_3d_name = model_3d_name.replace(".", "")
+ # print (model_3d_name);stop
nbrModel = None
- if s.Label.rfind('_') < s.Label.rfind('['):
- #ts = s.Label[s.Label.rfind('_')+1:s.Label.rfind('[')]
- nbrModel = s.Label[s.Label.rfind('['):]
- #print(nbrModel)
- nMd = int(nbrModel.replace('[','').replace(']',''))-1
+ if s.Label.rfind("_") < s.Label.rfind("["):
+ # ts = s.Label[s.Label.rfind('_')+1:s.Label.rfind('[')]
+ nbrModel = s.Label[s.Label.rfind("[") :]
+ # print(nbrModel)
+ nMd = int(nbrModel.replace("[", "").replace("]", "")) - 1
else:
- #ts = s.Label[s.Label.rfind('_')+1:]
+ # ts = s.Label[s.Label.rfind('_')+1:]
nMd = 0
- #print('nbrModel = 0')
- idxF=-1
- for i,mdl in enumerate (mdls):
- #print (mdl,nMd)
- #print(mdl[10],':', mdl[12]-1,':',nMd)
- if tsp in str(mdl[10]) and mdl[12]-1 == nMd:
- #print('FOUND',mdl[10],':', mdl[12],':',nMd)
- #if nMd == mdl[12]:
- idxF=i
- FLayer=1.
- #print(mdl[4])
- pos_x=mdl[1]-off_x
- pos_y=mdl[2]-off_y
- rot=mdl[3]
- mdl_layer=mdl[4]
- wrl_pos=mdl[6]
- wrl_rot=mdl[7]
- #print(mdl[10])
- #print(mdl[12])
- #print(wrl_pos)
- #print(wrl_rot)
+ # print('nbrModel = 0')
+ for i, mdl in enumerate(mdls):
+ # print (mdl,nMd)
+ # print(mdl[10],':', mdl[12]-1,':',nMd)
+ if tsp in str(mdl[10]) and mdl[12] - 1 == nMd:
+ # print('FOUND',mdl[10],':', mdl[12],':',nMd)
+ # if nMd == mdl[12]:
+ FLayer = 1.0
+ # print(mdl[4])
+ pos_x = mdl[1] - off_x
+ pos_y = mdl[2] - off_y
+ rot = mdl[3]
+ mdl_layer = mdl[4]
+ wrl_pos = mdl[6]
+ wrl_rot = mdl[7]
+ # print(mdl[10])
+ # print(mdl[12])
+ # print(wrl_pos)
+ # print(wrl_rot)
if wrl_rot[0] != 0:
- sayw('3D model X rotation != 0 (rotX='+str(wrl_rot[0])+')')
+ sayw("3D model X rotation != 0 (rotX=" + str(wrl_rot[0]) + ")")
if wrl_rot[1] != 0:
- sayw('3D model Y rotation != 0 (rotY='+str(wrl_rot[0])+')')
+ sayw("3D model Y rotation != 0 (rotY=" + str(wrl_rot[0]) + ")")
dummyshape = Part.Shape()
- print(s.Label,': model found! Placing it!')
- if 'Top' not in mdl_layer:
- FLayer=-1.
- if FLayer==1.:
- #ang = float(rot)
- #dummyshape.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x,pos_y,-pcbThickness),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
+ print(s.Label, ": model found! Placing it!")
+ if "Top" not in mdl_layer:
+ FLayer = -1.0
+ if FLayer == 1.0:
+ # ang = float(rot)
+ # dummyshape.Placement = FreeCAD.Placement(FreeCAD.Vector(pos_x,pos_y,-pcbThickness),FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180))
##FreeCAD.ActiveDocument.getObject(s.Name).Placement.Rotation=FreeCAD.Rotation(FreeCAD.Vector(0,0,1),ang)
- dummyshape.Placement=FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,0+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1]),-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
- dummyshape.rotate((pos_x,pos_y,0),(0,0,1),rot+float(wrl_rot[2]))
- FreeCAD.ActiveDocument.getObject(s.Name).Placement=dummyshape.Placement
- #bbpa=degrees(FreeCAD.ActiveDocument.getObject(s.Name).Placement.Rotation.Angle)
- #print(bbpa);#stop
- #if FreeCAD.ActiveDocument.getObject(s.Name).Placement.Rotation.Axis.z == -1:
+ dummyshape.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(
+ pos_x + float(wrl_pos[0]) * 25.4,
+ pos_y + float(wrl_pos[1]) * 25.4,
+ 0 + float(wrl_pos[2]) * 25.4,
+ ),
+ FreeCAD.Rotation(-float(wrl_rot[2]), -float(wrl_rot[1]), -float(wrl_rot[0])),
+ ) # rot is already rot fp -rot wrl
+ dummyshape.rotate((pos_x, pos_y, 0), (0, 0, 1), rot + float(wrl_rot[2]))
+ FreeCAD.ActiveDocument.getObject(s.Name).Placement = dummyshape.Placement
+ # bbpa=degrees(FreeCAD.ActiveDocument.getObject(s.Name).Placement.Rotation.Angle)
+ # print(bbpa);#stop
+ # if FreeCAD.ActiveDocument.getObject(s.Name).Placement.Rotation.Axis.z == -1:
# bbpa=-bbpa
- #new_angle=bbpa+z_rot
+ # new_angle=bbpa+z_rot
else:
- #print('bottom')
- dummyshape.Placement=FreeCAD.Placement(FreeCAD.Vector(pos_x+float(wrl_pos[0])*25.4,pos_y+float(wrl_pos[1])*25.4,+pcbThickness+float(wrl_pos[2])*25.4),FreeCAD.Rotation(-float(wrl_rot[2]),-float(wrl_rot[1]),-float(wrl_rot[0]))) #rot is already rot fp -rot wrl
- dummyshape.rotate((pos_x,pos_y,0),(0,0,1),180+rot+float(wrl_rot[2]))
- dummyshape.rotate((pos_x,pos_y,0),(0,1,0),180)
- FreeCAD.ActiveDocument.getObject(s.Name).Placement=dummyshape.Placement
+ # print('bottom')
+ dummyshape.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(
+ pos_x + float(wrl_pos[0]) * 25.4,
+ pos_y + float(wrl_pos[1]) * 25.4,
+ +pcbThickness + float(wrl_pos[2]) * 25.4,
+ ),
+ FreeCAD.Rotation(-float(wrl_rot[2]), -float(wrl_rot[1]), -float(wrl_rot[0])),
+ ) # rot is already rot fp -rot wrl
+ dummyshape.rotate((pos_x, pos_y, 0), (0, 0, 1), 180 + rot + float(wrl_rot[2]))
+ dummyshape.rotate((pos_x, pos_y, 0), (0, 1, 0), 180)
+ FreeCAD.ActiveDocument.getObject(s.Name).Placement = dummyshape.Placement
# bbpa=round(FreeCAD.ActiveDocument.getObject(s.Name).Placement.Rotation.toEuler()[0],1)
break
+
+
#
##
-def push3D2pcb(s,cnt,tsp):
- #global last_fp_path, test_flag, start_time
- #global configParser, configFilePath, start_time
- #global ignore_utf8, ignore_utf8_incfg, disable_PoM_Observer
+def push3D2pcb(s, cnt, tsp):
+ # global last_fp_path, test_flag, start_time
+ # global configParser, configFilePath, start_time
+ # global ignore_utf8, ignore_utf8_incfg, disable_PoM_Observer
global start_time, aux_orig, grid_orig
global board_base_point_x, board_base_point_y, real_board_pos_x, real_board_pos_y
- #global pcb_path, use_AppPart, force_oldGroups, use_Links
- #global original_filename, aux_orig, grid_orig
+ # global pcb_path, use_AppPart, force_oldGroups, use_Links
+ # global original_filename, aux_orig, grid_orig
global off_x, off_y, maxRadius
-
- #sayw('pushing 3D model moved to pcb')
- doc=FreeCAD.ActiveDocument
- data=u''.join(cnt)
- tstamp_found=False
+
+ # sayw('pushing 3D model moved to pcb')
+ data = "".join(cnt)
+ tstamp_found = False
if 0:
- #if len(re.findall('\s\(tstamp(.+?)\)',data, re.MULTILINE|re.DOTALL))>0:
- #if len(re.findall('\s\(tstamp(\s'+s.TimeStamp+'.+?)\)',data, re.MULTILINE|re.DOTALL))>0:
- #if len(re.findall('\s\(tstamp(\s'+tsp+'.+?)\)',data, re.MULTILINE|re.DOTALL))>0:
- if len(re.findall('\s\(tstamp(\s.*'+tsp.lower()+'+\))',data, re.MULTILINE|re.DOTALL))>0 or \
- len(re.findall('\s\(tstamp(\s.*'+tsp.upper()+'+\))',data, re.MULTILINE|re.DOTALL))>0: #kv6 puts tstamp in lower case
- #if len(re.findall('\s\(tstamp(\s'+tsp+'.+?)\)',data, re.MULTILINE|re.DOTALL))>0:
- tstamp_found=True
- #old_pos=re.findall('\s\(tstamp(\s'+sel[0].TimeStamp+'.+?'+'\(at'+'\s.+?)\)',data, re.MULTILINE|re.DOTALL)[0]
- #print (old_pos)
+ # if len(re.findall('\s\(tstamp(.+?)\)',data, re.MULTILINE|re.DOTALL))>0:
+ # if len(re.findall('\s\(tstamp(\s'+s.TimeStamp+'.+?)\)',data, re.MULTILINE|re.DOTALL))>0:
+ # if len(re.findall('\s\(tstamp(\s'+tsp+'.+?)\)',data, re.MULTILINE|re.DOTALL))>0:
+ if (
+ len(re.findall(r"\s\(tstamp(\s.*" + tsp.lower() + r"+\))", data, re.MULTILINE | re.DOTALL)) > 0
+ or len(re.findall(r"\s\(tstamp(\s.*" + tsp.upper() + r"+\))", data, re.MULTILINE | re.DOTALL)) > 0
+ ): # kv6 puts tstamp in lower case
+ # if len(re.findall('\s\(tstamp(\s'+tsp+'.+?)\)',data, re.MULTILINE|re.DOTALL))>0:
+ tstamp_found = True
+ # old_pos=re.findall('\s\(tstamp(\s'+sel[0].TimeStamp+'.+?'+'\(at'+'\s.+?)\)',data, re.MULTILINE|re.DOTALL)[0]
+ # print (old_pos)
# new_pos=old_pos.split('(at')[0]+'(at 1.23 5.67 890'
- elif len(re.findall('\s*\(uuid(\s.*'+tsp.lower()+'\"*\))',data, re.MULTILINE|re.DOTALL))>0 or \
- len(re.findall('\s*\(uuid(\s.*'+tsp.upper()+'\"*\))',data, re.MULTILINE|re.DOTALL))>0: #kv6 puts tstamp in lower case kv8 new mode '"'
+ elif (
+ len(re.findall(r"\s*\(uuid(\s.*" + tsp.lower() + '"*\\))', data, re.MULTILINE | re.DOTALL)) > 0
+ or len(re.findall(r"\s*\(uuid(\s.*" + tsp.upper() + '"*\\))', data, re.MULTILINE | re.DOTALL)) > 0
+ ): # kv6 puts tstamp in lower case kv8 new mode '"'
#'\s\(uuid(\s.*'+tsp.lower()+'+\))',data, re.MULTILINE|re.DOTALL))>0 or \
#'\s\(uuid(\s.*'+tsp.upper()+'+\))',data, re.MULTILINE|re.DOTALL))>0: #kv6 puts tstamp in lower case
- tstamp_found=True
+ tstamp_found = True
else:
- for i,ln in enumerate (cnt):
- if '(tstamp ' in ln or '(uuid' in ln:
- if tsp.lower() in ln or tsp.upper() in ln:
- tstamp_found=True
-
+ for i, ln in enumerate(cnt):
+ if ("(tstamp " in ln or "(uuid" in ln) and (tsp.lower() in ln or tsp.upper() in ln):
+ tstamp_found = True
+
if tstamp_found:
- oft=None
+ oft = None
if aux_orig == 1:
- oft=getAuxOrigin(data)
+ oft = getAuxOrigin(data)
if grid_orig == 1:
- oft=getGridOrigin(data)
- #print oft
- gof=False
+ oft = getGridOrigin(data)
+ # print oft
+ gof = False
if oft is not None:
- off_x=oft[0];off_y=-oft[1]
- offset = oft
- gof=True
- bbpx=FreeCAD.ActiveDocument.getObject(s.Name).Placement.Base[0]
- bbpy=FreeCAD.ActiveDocument.getObject(s.Name).Placement.Base[1]
- offset=[bbpx,bbpy]
- #print(bbpx);print(bbpy);print(bbpa)
- if gof and grid_orig==1:
- offset=[off_x,-off_y]
- #print(offset)
- #print (bbpx+off_x);print (-1*(bbpy+off_y))
- model_3d_name = s.Label[s.Label.find('_')+1:s.Label.rfind('_')]
- model_3d_name = model_3d_name.replace('.','')
- #print (model_3d_name);stop
- if s.Label.rfind('_') < s.Label.rfind('['):
- #ts = s.Label[s.Label.rfind('_')+1:s.Label.rfind('[')]
- nbrModel = s.Label[s.Label.rfind('['):]
- nMd = int(nbrModel.replace('[','').replace(']',''))-1
+ off_x = oft[0]
+ off_y = -oft[1]
+ gof = True
+ bbpx = FreeCAD.ActiveDocument.getObject(s.Name).Placement.Base[0]
+ bbpy = FreeCAD.ActiveDocument.getObject(s.Name).Placement.Base[1]
+ # print(bbpx);print(bbpy);print(bbpa)
+ if gof and grid_orig == 1:
+ pass
+ # print(offset)
+ # print (bbpx+off_x);print (-1*(bbpy+off_y))
+ model_3d_name = s.Label[s.Label.find("_") + 1 : s.Label.rfind("_")]
+ model_3d_name = model_3d_name.replace(".", "")
+ # print (model_3d_name);stop
+ if s.Label.rfind("_") < s.Label.rfind("["):
+ # ts = s.Label[s.Label.rfind('_')+1:s.Label.rfind('[')]
+ nbrModel = s.Label[s.Label.rfind("[") :]
+ nMd = int(nbrModel.replace("[", "").replace("]", "")) - 1
else:
- #ts = s.Label[s.Label.rfind('_')+1:]
+ # ts = s.Label[s.Label.rfind('_')+1:]
nMd = 0
- idxF=-1
- for i,ln in enumerate (cnt):
- #if '(tstamp '+s.TimeStamp in ln:
- #if '(tstamp '+tsp in ln:
- if '(tstamp ' in ln or '(uuid' in ln:
- if tsp in ln:
- idxF=i
- #print(ln)
- FLayer=1.
- if idxF>=0:
+ idxF = -1
+ for i, ln in enumerate(cnt):
+ # if '(tstamp '+s.TimeStamp in ln:
+ # if '(tstamp '+tsp in ln:
+ if ("(tstamp " in ln or "(uuid" in ln) and tsp in ln:
+ idxF = i
+ # print(ln)
+ FLayer = 1.0
+ if idxF >= 0:
print(s.Label)
- sayw('pushing 3D model moved to pcb')
- if 'Front' not in cnt[idxF]:
- FLayer=-1.
- if FLayer==1.:
- bbpa=degrees(FreeCAD.ActiveDocument.getObject(s.Name).Placement.Rotation.Angle)
- #print(bbpa);#stop
+ sayw("pushing 3D model moved to pcb")
+ if "Front" not in cnt[idxF]:
+ FLayer = -1.0
+ if FLayer == 1.0:
+ bbpa = degrees(FreeCAD.ActiveDocument.getObject(s.Name).Placement.Rotation.Angle)
+ # print(bbpa);#stop
if FreeCAD.ActiveDocument.getObject(s.Name).Placement.Rotation.Axis.z == -1:
- bbpa=-bbpa
- #new_angle=bbpa+z_rot
+ bbpa = -bbpa
+ # new_angle=bbpa+z_rot
else:
- bbpa=round(FreeCAD.ActiveDocument.getObject(s.Name).Placement.Rotation.toEuler()[0],1)
- #new_angle=bbpa+z_rot
- #say (content[idxF+1])
- #if 'Front' not in cnt[idxF]:
+ bbpa = round(FreeCAD.ActiveDocument.getObject(s.Name).Placement.Rotation.toEuler()[0], 1)
+ # new_angle=bbpa+z_rot
+ # say (content[idxF+1])
+ # if 'Front' not in cnt[idxF]:
# FLayer=-1.
mod_old_angle = 0
- mod_old_values = cnt[idxF+1].split('(at ')[1].split(' ')
- #sayw(mod_old_values)
+ mod_old_values = cnt[idxF + 1].split("(at ")[1].split(" ")
+ # sayw(mod_old_values)
if len(mod_old_values) == 3:
- mod_old_angle= (mod_old_values[2].split(')'))[0]
- mod_old_angle = mod_old_angle.replace(' ','')
- #print (mod_old_angle)
- if len(mod_old_angle) > 0:
- mod_old_angle=float("{0:.3f}".format(float(mod_old_angle)))
- else:
- mod_old_angle = 0
- #say ('module old angle '+str(mod_old_angle))
- nbr_spaces = len(cnt[idxF+1]) - len(cnt[idxF+1].lstrip())
- #new_pos="{0:.3f}".format(bbpx+off_x)+" "+"{0:.3f}".format(-1*(bbpy+off_y))+\
+ mod_old_angle = (mod_old_values[2].split(")"))[0]
+ mod_old_angle = mod_old_angle.replace(" ", "")
+ # print (mod_old_angle)
+ mod_old_angle = float(f"{float(mod_old_angle):.3f}") if len(mod_old_angle) > 0 else 0
+ # say ('module old angle '+str(mod_old_angle))
+ nbr_spaces = len(cnt[idxF + 1]) - len(cnt[idxF + 1].lstrip())
+ # new_pos="{0:.3f}".format(bbpx+off_x)+" "+"{0:.3f}".format(-1*(bbpy+off_y))+\
# " "+"{0:.3f}".format(bbpa)+")"
-# " "+"{0:.3f}".format(bbpa-mod_old_angle)+")"
- #print(new_pos)
+ # " "+"{0:.3f}".format(bbpa-mod_old_angle)+")"
+ # print(new_pos)
##cnt[idxF+1]=" " * nbr_spaces + '(at '+new_pos+os.linesep
- #say (content[idxF+1])
- looping=True;ik=0
- pads_2rot=[];old_ref_angle=None;old_val_angle=None;old_usr_angle=None
+ # say (content[idxF+1])
+ looping = True
+ ik = 0
+ pads_2rot = []
+ old_ref_angle = None
+ old_val_angle = None
+ old_usr_angle = None
nMdCnt = 0
- while looping and (idxF+ik) < len(cnt):
- #for ln in content[idxF+1:]:
- ik+=1
- ln = cnt[idxF+ik]
- if '(model' in ln:
- if nMdCnt==nMd:
- #looping=False
+ while looping and (idxF + ik) < len(cnt):
+ # for ln in content[idxF+1:]:
+ ik += 1
+ ln = cnt[idxF + ik]
+ if "(model" in ln:
+ if nMdCnt == nMd:
+ # looping=False
##if model_3d_name in ln.replace('.',''): #removing '.' not imported by STEP
- #print(ln);print(cnt[idxF+ik+3]);stop
- #print(ln);print(cnt[idxF+ik+3]);print(nMdCnt)#;stop
- ln_r=cnt[idxF+ik+1]
+ # print(ln);print(cnt[idxF+ik+3]);stop
+ # print(ln);print(cnt[idxF+ik+3]);print(nMdCnt)#;stop
+ ln_r = cnt[idxF + ik + 1]
# (offset (xyz -1.27 0 0)) mm
# (at (xyz -1.27/25.4 0 0)) decimils
- if 'at' in ln_r:
- k=25.40
- else:
- k=1.0
- ido = ln_r.find('xyz');ofs=ln_r[ido+3:] #lstrip('xyz')
- ido = ofs.find('))');ofs=ofs[:ido]
- ofs = ofs.lstrip(' ').split(' ')
- #sayerr(ofs)
- if len(ofs)==3:
- x_o=float(ofs[0])*k
- y_o=float(ofs[1])*k
- z_o=float(ofs[2])*k
+ k = 25.4 if "at" in ln_r else 1.0
+ ido = ln_r.find("xyz")
+ ofs = ln_r[ido + 3 :] # lstrip('xyz')
+ ido = ofs.find("))")
+ ofs = ofs[:ido]
+ ofs = ofs.lstrip(" ").split(" ")
+ # sayerr(ofs)
+ if len(ofs) == 3:
+ x_o = float(ofs[0]) * k
+ y_o = float(ofs[1]) * k
+ float(ofs[2]) * k
else:
- x_o=0;y_o=0;z_o=0
- #sayw(ofs)
- ln_r=cnt[idxF+ik+3]
+ x_o = 0
+ y_o = 0
+ # sayw(ofs)
+ ln_r = cnt[idxF + ik + 3]
# (rotate (xyz 0 0 0))
- #print(ln_r)#;stop
- idz1 = ln_r.find('xyz');z_rot=ln_r[idz1+3:] #lstrip('xyz')
- idz2 = z_rot.find('))');z_rot=z_rot[:idz2]
- #z_rot = z_rot.rstrip('))')
- z_rot = z_rot.lstrip(' ').split(' ')
- #sayerr(z_rot)
- if len(z_rot)==3:
- all_rot=z_rot
- z_rot2_p=z_rot[2].rfind(")")
+ # print(ln_r)#;stop
+ idz1 = ln_r.find("xyz")
+ z_rot = ln_r[idz1 + 3 :] # lstrip('xyz')
+ idz2 = z_rot.find("))")
+ z_rot = z_rot[:idz2]
+ # z_rot = z_rot.rstrip('))')
+ z_rot = z_rot.lstrip(" ").split(" ")
+ # sayerr(z_rot)
+ if len(z_rot) == 3:
+ all_rot = z_rot
+ z_rot2_p = z_rot[2].rfind(")")
if z_rot2_p != -1:
z_rot2 = z_rot[2]
z_rot2 = z_rot2[0:z_rot2_p]
- z_rot=float(z_rot2)
+ z_rot = float(z_rot2)
else:
- z_rot=float(z_rot[2])
- #z_rot=float(z_rot[2])
+ z_rot = float(z_rot[2])
+ # z_rot=float(z_rot[2])
if float(all_rot[0]) != 0:
- sayerr('3D model X rotation NOT supported ATM!')
- sayw('X rot='+all_rot[0])
- msg="""3D model X rotation NOT supported ATM!
Please fix your 3D model rotation X to '0'"""
+ sayerr("3D model X rotation NOT supported ATM!")
+ sayw("X rot=" + all_rot[0])
+ msg = """3D model X rotation NOT supported ATM!
Please fix your 3D model rotation X to '0'"""
say_warning(msg)
stop
if float(all_rot[1]) != 0:
- sayerr('3D model Y rotation NOT supported ATM!')
- sayw('Y rot='+all_rot[1])
- msg="""3D model Y rotation NOT supported ATM!
Please fix your 3D model rotation Y to '0'"""
+ sayerr("3D model Y rotation NOT supported ATM!")
+ sayw("Y rot=" + all_rot[1])
+ msg = """3D model Y rotation NOT supported ATM!
Please fix your 3D model rotation Y to '0'"""
say_warning(msg)
stop
else:
- z_rot=0
- #print(z_rot);stop
- #sayw(z_rot)
- looping=False
+ z_rot = 0
+ # print(z_rot);stop
+ # sayw(z_rot)
+ looping = False
else:
- nMdCnt+=1
- if '(pad ' in ln:
+ nMdCnt += 1
+ if "(pad " in ln:
# print (ln)
- #print (ln.split('(at ')[1].split(')')[0].split(' '))
- if '(at ' in ln: # pre kv8
- pad_values=ln.split('(at ')[1].split(')')[0].split(' ')
+ # print (ln.split('(at ')[1].split(')')[0].split(' '))
+ if "(at " in ln: # pre kv8
+ pad_values = ln.split("(at ")[1].split(")")[0].split(" ")
else:
- ln_n=cnt[idxF+ik+1]
- pad_values=ln_n.split('(at ')[1].split(')')[0].split(' ')
+ ln_n = cnt[idxF + ik + 1]
+ pad_values = ln_n.split("(at ")[1].split(")")[0].split(" ")
if len(pad_values) == 3:
- #print(pad_values[2])
- old_pad_angle = (float(pad_values[2]))
+ # print(pad_values[2])
+ old_pad_angle = float(pad_values[2])
else:
old_pad_angle = 0
base_pad_angle = old_pad_angle - mod_old_angle
- id_pad = idxF+ik
- pads_2rot.append([base_pad_angle,id_pad,pad_values])
- #print(content[idxF+ik])
- if '(fp_text reference' in ln or '(property "Reference"' in ln:
- #print (ln)
- #print (ln.split('(at ')[1].split(')')[0].split(' '))
- if '(at ' in ln: # pre kv8
- ref_values=ln.split('(at ')[1].split(')')[0].split(' ')
+ id_pad = idxF + ik
+ pads_2rot.append([base_pad_angle, id_pad, pad_values])
+ # print(content[idxF+ik])
+ if "(fp_text reference" in ln or '(property "Reference"' in ln:
+ # print (ln)
+ # print (ln.split('(at ')[1].split(')')[0].split(' '))
+ if "(at " in ln: # pre kv8
+ ref_values = ln.split("(at ")[1].split(")")[0].split(" ")
else:
- ln_n=cnt[idxF+ik+1]
- ref_values=ln_n.split('(at ')[1].split(')')[0].split(' ')
+ ln_n = cnt[idxF + ik + 1]
+ ref_values = ln_n.split("(at ")[1].split(")")[0].split(" ")
old_ref_angle = 0
if len(ref_values) == 3:
- #print(pad_values[2])
- #print(ref_values[2])
- if ref_values[2] != 'unlocked':
- old_ref_angle = (float(ref_values[2]))
- #else:
+ # print(pad_values[2])
+ # print(ref_values[2])
+ if ref_values[2] != "unlocked":
+ old_ref_angle = float(ref_values[2])
+ # else:
# old_ref_angle = 0
- #print (pad_values);print(ln.split('(at '))
+ # print (pad_values);print(ln.split('(at '))
base_ref_angle = old_ref_angle - mod_old_angle
- new_ref_angle = ' '+("{0:.3f}".format(base_ref_angle + bbpa))
+ new_ref_angle = " " + (f"{base_ref_angle + bbpa:.3f}")
if float(new_ref_angle) == 0:
- new_ref_angle=''
- #print (pad_values);print(ln.split('(at '))
- idx_ref=idxF+ik
- if '(at ' in ln: # pre kv8
- cnt[idxF+ik] = ln.split('(at ')[0]+'(at ' + ref_values[0] +' '+ ref_values[1]+new_ref_angle+ln[ln.index(') '):]
+ new_ref_angle = ""
+ # print (pad_values);print(ln.split('(at '))
+ idx_ref = idxF + ik
+ if "(at " in ln: # pre kv8
+ cnt[idxF + ik] = (
+ ln.split("(at ")[0]
+ + "(at "
+ + ref_values[0]
+ + " "
+ + ref_values[1]
+ + new_ref_angle
+ + ln[ln.index(") ") :]
+ )
else:
- ln_n=cnt[idxF+ik+1]
- cnt[idxF+ik+1] = ln_n.split('(at ')[0]+'(at ' + ref_values[0] +' '+ ref_values[1]+new_ref_angle+ln_n[ln_n.index(')'):]
- if '(fp_text value' in ln or '(property "Value"' in ln:
- #print (ln)
- #print (ln.split('(at ')[1].split(')')[0].split(' '))
- if '(at ' in ln: # pre kv8
- val_values=ln.split('(at ')[1].split(')')[0].split(' ')
+ ln_n = cnt[idxF + ik + 1]
+ cnt[idxF + ik + 1] = (
+ ln_n.split("(at ")[0]
+ + "(at "
+ + ref_values[0]
+ + " "
+ + ref_values[1]
+ + new_ref_angle
+ + ln_n[ln_n.index(")") :]
+ )
+ if "(fp_text value" in ln or '(property "Value"' in ln:
+ # print (ln)
+ # print (ln.split('(at ')[1].split(')')[0].split(' '))
+ if "(at " in ln: # pre kv8
+ val_values = ln.split("(at ")[1].split(")")[0].split(" ")
else:
- ln_n=cnt[idxF+ik+1]
- val_values=ln_n.split('(at ')[1].split(')')[0].split(' ')
+ ln_n = cnt[idxF + ik + 1]
+ val_values = ln_n.split("(at ")[1].split(")")[0].split(" ")
old_val_angle = 0
if len(val_values) == 3:
- #print(pad_values[2])
- if val_values[2] != 'unlocked':
- old_val_angle = (float(val_values[2]))
- #else:
+ # print(pad_values[2])
+ if val_values[2] != "unlocked":
+ old_val_angle = float(val_values[2])
+ # else:
# old_val_angle = 0
base_val_angle = old_val_angle - mod_old_angle
- new_val_angle = ' '+("{0:.3f}".format(base_val_angle + bbpa))
+ new_val_angle = " " + (f"{base_val_angle + bbpa:.3f}")
if float(new_val_angle) == 0:
- new_val_angle=''
- #print (pad_values);print(ln.split('(at '))
- idx_val=idxF+ik
- if '(at ' in ln: # pre kv8
- cnt[idxF+ik] = ln.split('(at ')[0]+'(at ' + val_values[0] +' '+ val_values[1]+new_val_angle+ln[ln.index(') '):]
+ new_val_angle = ""
+ # print (pad_values);print(ln.split('(at '))
+ idx_val = idxF + ik
+ if "(at " in ln: # pre kv8
+ cnt[idxF + ik] = (
+ ln.split("(at ")[0]
+ + "(at "
+ + val_values[0]
+ + " "
+ + val_values[1]
+ + new_val_angle
+ + ln[ln.index(") ") :]
+ )
else:
- ln_n=cnt[idxF+ik+1]
- cnt[idxF+ik+1] = ln_n.split('(at ')[0]+'(at ' + val_values[0] +' '+ val_values[1]+new_val_angle+ln_n[ln_n.index(')'):]
- if '(fp_text user' in ln:
- #print (ln)
- #print (ln.split('(at ')[1].split(')')[0].split(' '))
- if '(at ' in ln: # pre kv8
- usr_values=ln.split('(at ')[1].split(')')[0].split(' ')
+ ln_n = cnt[idxF + ik + 1]
+ cnt[idxF + ik + 1] = (
+ ln_n.split("(at ")[0]
+ + "(at "
+ + val_values[0]
+ + " "
+ + val_values[1]
+ + new_val_angle
+ + ln_n[ln_n.index(")") :]
+ )
+ if "(fp_text user" in ln:
+ # print (ln)
+ # print (ln.split('(at ')[1].split(')')[0].split(' '))
+ if "(at " in ln: # pre kv8
+ usr_values = ln.split("(at ")[1].split(")")[0].split(" ")
else:
- ln_n=cnt[idxF+ik+1]
- usr_values=ln_n.split('(at ')[1].split(')')[0].split(' ')
+ ln_n = cnt[idxF + ik + 1]
+ usr_values = ln_n.split("(at ")[1].split(")")[0].split(" ")
old_usr_angle = 0
if len(usr_values) == 3:
- #print(pad_values[2])
- if usr_values[2] != 'unlocked':
- old_usr_angle = (float(usr_values[2]))
- #else:
+ # print(pad_values[2])
+ if usr_values[2] != "unlocked":
+ old_usr_angle = float(usr_values[2])
+ # else:
# old_usr_angle = 0
base_usr_angle = old_usr_angle - mod_old_angle
- new_usr_angle = ' '+("{0:.3f}".format(base_usr_angle + bbpa))
+ new_usr_angle = " " + (f"{base_usr_angle + bbpa:.3f}")
if float(new_usr_angle) == 0:
- new_usr_angle=''
- #print (pad_values);print(ln.split('(at '))
- idx_usr=idxF+ik
- if '(at ' in ln: # pre kv8
- cnt[idxF+ik] = ln.split('(at ')[0]+'(at ' + usr_values[0] +' '+ usr_values[1]+new_usr_angle+ln[ln.index(') '):]
+ new_usr_angle = ""
+ # print (pad_values);print(ln.split('(at '))
+ idx_usr = idxF + ik
+ if "(at " in ln: # pre kv8
+ cnt[idxF + ik] = (
+ ln.split("(at ")[0]
+ + "(at "
+ + usr_values[0]
+ + " "
+ + usr_values[1]
+ + new_usr_angle
+ + ln[ln.index(") ") :]
+ )
else:
- ln_n=cnt[idxF+ik+1]
- cnt[idxF+ik+1] = ln_n.split('(at ')[0]+'(at ' + usr_values[0] +' '+ usr_values[1]+new_usr_angle+ln_n[ln_n.index(')'):]
- #adjusting footprint
- if FLayer==1.:
- new_angle=bbpa+z_rot
+ ln_n = cnt[idxF + ik + 1]
+ cnt[idxF + ik + 1] = (
+ ln_n.split("(at ")[0]
+ + "(at "
+ + usr_values[0]
+ + " "
+ + usr_values[1]
+ + new_usr_angle
+ + ln_n[ln_n.index(")") :]
+ )
+ # adjusting footprint
+ if FLayer == 1.0:
+ new_angle = bbpa + z_rot
else:
- new_angle=(bbpa-z_rot) # 180+(bbpa+z_rot)
- #new_angle=bbpa+z_rot
- if "{0:.3f}".format(new_angle) == '-0.00' or "{0:.3f}".format(new_angle) == '0.00':
- new_angle_str=''
+ new_angle = bbpa - z_rot # 180+(bbpa+z_rot)
+ # new_angle=bbpa+z_rot
+ if f"{new_angle:.3f}" == "-0.00" or f"{new_angle:.3f}" == "0.00":
+ new_angle_str = ""
else:
- new_angle_str = ' '+"{0:.3f}".format(new_angle)
- new_pos="{0:.3f}".format(bbpx+off_x-x_o*FLayer)+" "+"{0:.3f}".format(-1*(bbpy+off_y-y_o*FLayer))\
- +new_angle_str+")"
- #print(new_pos)
- cnt[idxF+1]=" " * nbr_spaces + '(at '+new_pos+os.linesep
- #adjusting reference
+ new_angle_str = " " + f"{new_angle:.3f}"
+ new_pos = (
+ f"{bbpx + off_x - x_o * FLayer:.3f}"
+ + " "
+ + f"{-1 * (bbpy + off_y - y_o * FLayer):.3f}"
+ + new_angle_str
+ + ")"
+ )
+ # print(new_pos)
+ cnt[idxF + 1] = " " * nbr_spaces + "(at " + new_pos + os.linesep
+ # adjusting reference
if old_ref_angle is not None:
- base_ref_angle = old_ref_angle - mod_old_angle # - z_rot
- new_ref_angle = ' '+("{0:.3f}".format(base_ref_angle + bbpa + z_rot))
+ base_ref_angle = old_ref_angle - mod_old_angle # - z_rot
+ new_ref_angle = " " + (f"{base_ref_angle + bbpa + z_rot:.3f}")
if float(new_ref_angle) == 0:
- new_ref_angle=''
- ln=cnt[idx_ref]
- if ('(at' in ln): # pre kv8
- cnt[idx_ref] = ln.split('(at ')[0]+'(at ' + ref_values[0] +' '+ ref_values[1]+new_ref_angle+ln[ln.index(') '):]
+ new_ref_angle = ""
+ ln = cnt[idx_ref]
+ if "(at" in ln: # pre kv8
+ cnt[idx_ref] = (
+ ln.split("(at ")[0]
+ + "(at "
+ + ref_values[0]
+ + " "
+ + ref_values[1]
+ + new_ref_angle
+ + ln[ln.index(") ") :]
+ )
else:
- ln_n=cnt[idx_ref+1]
- cnt[idx_ref+1] = ln_n.split('(at ')[0]+'(at ' + ref_values[0] +' '+ ref_values[1]+new_ref_angle+ln_n[ln_n.index(')'):]
+ ln_n = cnt[idx_ref + 1]
+ cnt[idx_ref + 1] = (
+ ln_n.split("(at ")[0]
+ + "(at "
+ + ref_values[0]
+ + " "
+ + ref_values[1]
+ + new_ref_angle
+ + ln_n[ln_n.index(")") :]
+ )
if old_val_angle is not None:
- base_val_angle = old_val_angle - mod_old_angle #
- new_val_angle = ' '+("{0:.3f}".format(base_val_angle + bbpa + z_rot))
+ base_val_angle = old_val_angle - mod_old_angle
+ new_val_angle = " " + (f"{base_val_angle + bbpa + z_rot:.3f}")
if float(new_val_angle) == 0:
- new_val_angle=''
- ln=cnt[idx_val]
- if ('(at' in ln): # pre kv8
- cnt[idx_val] = ln.split('(at ')[0]+'(at ' + val_values[0] +' '+ val_values[1]+new_val_angle+ln[ln.index(') '):]
+ new_val_angle = ""
+ ln = cnt[idx_val]
+ if "(at" in ln: # pre kv8
+ cnt[idx_val] = (
+ ln.split("(at ")[0]
+ + "(at "
+ + val_values[0]
+ + " "
+ + val_values[1]
+ + new_val_angle
+ + ln[ln.index(") ") :]
+ )
else:
- ln_n=cnt[idx_val+1]
- cnt[idx_val+1] = ln_n.split('(at ')[0]+'(at ' + val_values[0] +' '+ val_values[1]+new_val_angle+ln_n[ln_n.index(')'):]
+ ln_n = cnt[idx_val + 1]
+ cnt[idx_val + 1] = (
+ ln_n.split("(at ")[0]
+ + "(at "
+ + val_values[0]
+ + " "
+ + val_values[1]
+ + new_val_angle
+ + ln_n[ln_n.index(")") :]
+ )
if old_usr_angle is not None:
- base_usr_angle = old_usr_angle - mod_old_angle #
- new_usr_angle = ' '+("{0:.3f}".format(base_usr_angle + bbpa + z_rot))
+ base_usr_angle = old_usr_angle - mod_old_angle
+ new_usr_angle = " " + (f"{base_usr_angle + bbpa + z_rot:.3f}")
if float(new_usr_angle) == 0:
- new_usr_angle=''
- ln=cnt[idx_usr]
- #print(ln)
- if ('(at' in ln): # pre kv8
- cnt[idx_usr] = ln.split('(at ')[0]+'(at ' + usr_values[0] +' '+ usr_values[1]+new_usr_angle+ln[ln.index(') '):]
+ new_usr_angle = ""
+ ln = cnt[idx_usr]
+ # print(ln)
+ if "(at" in ln: # pre kv8
+ cnt[idx_usr] = (
+ ln.split("(at ")[0]
+ + "(at "
+ + usr_values[0]
+ + " "
+ + usr_values[1]
+ + new_usr_angle
+ + ln[ln.index(") ") :]
+ )
else:
- ln_n=cnt[idx_usr+1]
- cnt[idx_usr+1] = ln_n.split('(at ')[0]+'(at ' + usr_values[0] +' '+ usr_values[1]+new_usr_angle+ln_n[ln_n.index(')'):]
- #print(new_ref_angle);print(old_ref_angle);print(z_rot);print(bbpa);print(base_ref_angle+bbpa);stop
+ ln_n = cnt[idx_usr + 1]
+ cnt[idx_usr + 1] = (
+ ln_n.split("(at ")[0]
+ + "(at "
+ + usr_values[0]
+ + " "
+ + usr_values[1]
+ + new_usr_angle
+ + ln_n[ln_n.index(")") :]
+ )
+ # print(new_ref_angle);print(old_ref_angle);print(z_rot);print(bbpa);print(base_ref_angle+bbpa);stop
for p2r in pads_2rot:
- new_pad_angle = ' '+("{0:.3f}".format(p2r[0] + bbpa + z_rot))
+ new_pad_angle = " " + (f"{p2r[0] + bbpa + z_rot:.3f}")
if float(new_pad_angle) == 0:
- new_pad_angle=''
- #print (pad_values);print(ln.split('(at '))
- ln = cnt[p2r[1]]
+ new_pad_angle = ""
+ # print (pad_values);print(ln.split('(at '))
+ ln = cnt[p2r[1]]
pad_val = p2r[2]
- #print(ln)
- if ('(at' in ln): # pre kv8
- cnt[p2r[1]] = ln.split('(at ')[0]+'(at ' + pad_val[0] +' '+ pad_val[1]+new_pad_angle+ln[ln.index(') '):]
+ # print(ln)
+ if "(at" in ln: # pre kv8
+ cnt[p2r[1]] = (
+ ln.split("(at ")[0]
+ + "(at "
+ + pad_val[0]
+ + " "
+ + pad_val[1]
+ + new_pad_angle
+ + ln[ln.index(") ") :]
+ )
else:
- ln_n=cnt[p2r[1]+1]
- #print(ln_n)
- cnt[p2r[1]+1] = ln_n.split('(at ')[0]+'(at ' + pad_val[0] +' '+ pad_val[1]+new_pad_angle+ln_n[ln_n.index(')'):]
- #stop # 'we need to search for pads in module and add rotation angle each'
- #stop
- #newdata=u''.join(content)
- newcontent=cnt
- #print newcontent
+ ln_n = cnt[p2r[1] + 1]
+ # print(ln_n)
+ cnt[p2r[1] + 1] = (
+ ln_n.split("(at ")[0]
+ + "(at "
+ + pad_val[0]
+ + " "
+ + pad_val[1]
+ + new_pad_angle
+ + ln_n[ln_n.index(")") :]
+ )
+ # stop # 'we need to search for pads in module and add rotation angle each'
+ # stop
+ # newdata=u''.join(content)
+ newcontent = cnt
+ # print newcontent
else:
- msg="footprint TimeStamp not found!
Please reload the kicad_pcb file"
+ msg = "footprint TimeStamp not found!
Please reload the kicad_pcb file"
say_warning(msg)
- newcontent=cnt
+ newcontent = cnt
# with codecs.open(fpath,'w', encoding='utf-8') as ofile:
# ofile.write(newcontent)
- # ofile.close()
+ # ofile.close()
# say_time()
# msg="""3D model new position pushed to kicad board!
"""
# if found_tracks:
@@ -22157,25 +24251,28 @@ def push3D2pcb(s,cnt,tsp):
# msgr+="backup file saved to "+foname
# say(msgr)
# #say_info(msg)
- return newcontent
+ return newcontent
+
+
##
+
###############################################################################################################
-def centerOnScreen (widget):
- '''centerOnScreen()
- Centers the window on the screen.'''
+def centerOnScreen(widget):
+ """centerOnScreen()
+ Centers the window on the screen."""
# sayw(widg.width());sayw(widg.height())
# sayw(widg.pos().x());sayw(widg.pos().y())
mainWin = FreeCAD.Gui.getMainWindow()
- #App.Console.PrintMessage(mainWin.geometry().center())
- #print(mainWin.geometry().center())
- xp=mainWin.geometry().center().x() - sizeX/2
- yp=mainWin.geometry().center().y() - sizeY/2
- centerPoint = QtCore.QPoint(xp - sizeXMax/2, yp)
- #Qt.point(center.x, center.y - half )
+ # App.Console.PrintMessage(mainWin.geometry().center())
+ # print(mainWin.geometry().center())
+ xp = mainWin.geometry().center().x() - sizeX / 2
+ yp = mainWin.geometry().center().y() - sizeY / 2
+ centerPoint = QtCore.QPoint(xp - sizeXMax / 2, yp)
+ # Qt.point(center.x, center.y - half )
fg = widget.frameGeometry()
fg.moveCenter(centerPoint)
- widget.move(fg.topLeft())
+ widget.move(fg.topLeft())
widget.setGeometry(xp, yp, sizeXMax, sizeY)
# if hasattr(QtGui.QGuiApplication, "primaryScreen"):
# resolution = QtGui.QGuiApplication.primaryScreen().availableGeometry()
@@ -22185,45 +24282,49 @@ def centerOnScreen (widget):
# yp=(resolution.height() / 2) - sizeY/2 # - (KSUWidget.frameSize().height() / 2))
# # xp=widg.pos().x()-sizeXMax/2;yp=widg.pos().y()#+sizeY/2
# widg.setGeometry(xp, yp, sizeXMax, sizeY)
+
+
##
+
def singleInstance():
- app = QtGui.QApplication #QtGui.qApp
+ app = QtGui.QApplication # QtGui.qApp
for i in app.topLevelWidgets():
- #say (str(i.objectName()))
+ # say (str(i.objectName()))
if i.objectName() == "kicadStepUp":
- say (str(i.objectName()))
- #i.close()
- #i.deleteLater()
- say ('closed')
+ say(str(i.objectName()))
+ # i.close()
+ # i.deleteLater()
+ say("closed")
return False
- t=FreeCADGui.getMainWindow()
- dw=t.findChildren(QtGui.QDockWidget)
- #say( str(dw) )
+ t = FreeCADGui.getMainWindow()
+ dw = t.findChildren(QtGui.QDockWidget)
+ # say( str(dw) )
for i in dw:
- #say (str(i.objectName()))
- if str(i.objectName()) == "kicadStepUp": #"kicad StepUp 3D tools":
- say (str(i.objectName())+' docked')
- #i.deleteLater()
+ # say (str(i.objectName()))
+ if str(i.objectName()) == "kicadStepUp": # "kicad StepUp 3D tools":
+ say(str(i.objectName()) + " docked")
+ # i.deleteLater()
return False
return True
+
+
##
if singleInstance():
-
from threading import Timer
-
- KSUWidget = QtGui.QDockWidget() # create a new dckwidget
- KSUWidget.ui = Ui_DockWidget() # myWidget_Ui() # load the Ui script
- KSUWidget.ui.setupUi(KSUWidget) # setup the ui
+
+ KSUWidget = QtGui.QDockWidget() # create a new dckwidget
+ KSUWidget.ui = Ui_DockWidget() # myWidget_Ui() # load the Ui script
+ KSUWidget.ui.setupUi(KSUWidget) # setup the ui
KSUWidget.setObjectName("kicadStepUp")
-
+
paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/MainWindow")
- if len(paramGet.GetString("StyleSheet"))>0: #we are using a StyleSheet
- KSUWidget.setStyleSheet('QPushButton {border-radius: 0px; padding: 1px 2px;}')
+ if len(paramGet.GetString("StyleSheet")) > 0: # we are using a StyleSheet
+ KSUWidget.setStyleSheet("QPushButton {border-radius: 0px; padding: 1px 2px;}")
- t=FreeCADGui.getMainWindow()
+ t = FreeCADGui.getMainWindow()
## wf = t.findChild(QtGui.QDockWidget, "KSUWidget")
cv = t.findChild(QtGui.QDockWidget, "Combo View")
if cv is None:
@@ -22233,80 +24334,81 @@ def singleInstance():
if cv is None:
cv = t.findChild(QtGui.QDockWidget, "Tree view")
if cv is None:
- cv = [o for o in t.children () if o.objectName () == "Combo View"]
- if cv:
- cv = cv[0]
- else:
- cv = None
- #say( "Combo View" + str(cv))
- ## print( "KSUWidget" + str(wf))
- cv.setFeatures( QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable|QtGui.QDockWidget.DockWidgetClosable )
- #KSUWidget.setFeatures( QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable|QtGui.QDockWidget.DockWidgetClosable )
- KSUWidget.setFeatures( QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable) #|QtGui.QDockWidget.DockWidgetClosable )
-
-
- ksu_in_tab=False
-
- #tabify_widg=True
- #tabify_widg=False
- #dock_to_right=True
-
-
- if docking_mode == 'float':
+ cv = [o for o in t.children() if o.objectName() == "Combo View"]
+ cv = cv[0] if cv else None
+ # say( "Combo View" + str(cv))
+ ## print( "KSUWidget" + str(wf))
+ cv.setFeatures(
+ QtGui.QDockWidget.DockWidgetMovable
+ | QtGui.QDockWidget.DockWidgetFloatable
+ | QtGui.QDockWidget.DockWidgetClosable,
+ )
+ # KSUWidget.setFeatures( QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable|QtGui.QDockWidget.DockWidgetClosable )
+ KSUWidget.setFeatures(
+ QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable,
+ ) # |QtGui.QDockWidget.DockWidgetClosable )
+
+ ksu_in_tab = False
+
+ # tabify_widg=True
+ # tabify_widg=False
+ # dock_to_right=True
+
+ if docking_mode == "float":
tabify()
undock()
- textEdit_dim=textEdit_dim_base
- KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
-
- elif docking_mode == 'left':
- textEdit_dim=textEdit_dim_hide
- KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
+ textEdit_dim = textEdit_dim_base
+ KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0], textEdit_dim[1], textEdit_dim[2], textEdit_dim[3])
+
+ elif docking_mode == "left":
+ textEdit_dim = textEdit_dim_hide
+ KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0], textEdit_dim[1], textEdit_dim[2], textEdit_dim[3])
dock()
##tabify()
- #.Visible=False
+ # .Visible=False
else:
- textEdit_dim=textEdit_dim_hide
- KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0],textEdit_dim[1],textEdit_dim[2],textEdit_dim[3])
+ textEdit_dim = textEdit_dim_hide
+ KSUWidget.ui.textEdit.setGeometry(textEdit_dim[0], textEdit_dim[1], textEdit_dim[2], textEdit_dim[3])
dock_right()
KSUWidget.activateWindow()
KSUWidget.raise_()
- sayw('done!')
-
+ sayw("done!")
- #if (tabify_widg):
+ # if (tabify_widg):
# tabify()
- #elif not dock_to_right:
- # #KSUmw = FreeCADGui.getMainWindow() # PySide # the active qt window, = the freecad window since we are inside it
+ # elif not dock_to_right:
+ # #KSUmw = FreeCADGui.getMainWindow() # PySide # the active qt window, = the freecad window since we are inside it
# tabify()
# undock()
- # #KSUmw.addDockWidget(QtCore.Qt.RightDockWidgetArea,KSUWidget) # add the widget to the main window
- #else:
+ # #KSUmw.addDockWidget(QtCore.Qt.RightDockWidgetArea,KSUWidget) # add the widget to the main window
+ # else:
# dock_right()
KSUWidget.activateWindow()
KSUWidget.raise_()
KSUWidget.hide()
-def getComboView(self,window):
- """ Returns the main Tab.
- """
- dw=window.findChildren(QtGui.QDockWidget)
+
+def getComboView(self, window):
+ """Returns the main Tab."""
+ dw = window.findChildren(QtGui.QDockWidget)
for i in dw:
if str(i.objectName()) == "Combo View" or str(i.objectName() == "Model") or str(i.objectName()) == "Tree view":
return i.findChild(QtGui.QTabWidget)
raise Exception("No tab widget found")
+
# QDockWidget::setFloating (false)
# KSUWidget.setFloating(True) #undock
-#KSUWidget.setFloating(False) #dock
+# KSUWidget.setFloating(False) #dock
-#KSUWidget.setStyleSheet('QPushButton { border: 1px solid #5a5a5a;border-radius: 0px;min-width: 50px;min-height: 20px;padding: 1px 2px;}')
-#KSUWidget.setStyleSheet('QPushButton:hover,QPushButton:focus { color: white; border-color: #3874f2; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #5e90fa, stop:1 #3874f2);}')
+# KSUWidget.setStyleSheet('QPushButton { border: 1px solid #5a5a5a;border-radius: 0px;min-width: 50px;min-height: 20px;padding: 1px 2px;}')
+# KSUWidget.setStyleSheet('QPushButton:hover,QPushButton:focus { color: white; border-color: #3874f2; background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:0, y2:1, stop:0 #5e90fa, stop:1 #3874f2);}')
-# print QtGui.QApplication.style().metaObject().className() #
-# print KSUWidget.style().metaObject().className() #
-# print QtGui.QApplication.instance().styleSheet() # list all applied styles
+# print QtGui.QApplication.style().metaObject().className() #
+# print KSUWidget.style().metaObject().className() #
+# print QtGui.QApplication.instance().styleSheet() # list all applied styles
# try:
# if KSUWidget.style().metaObject().className()== "QStyleSheetStyle":
@@ -22314,15 +24416,13 @@ def getComboView(self,window):
# except:
# pass
## QtGui.QFont().setPointSize(font_size) ???? to evaluate if still is necessary
-
-#Ui_DockWidget().destroyed.connect(onDestroy())
+
+# Ui_DockWidget().destroyed.connect(onDestroy())
## KSUWidget.installEventFilter(KSUWidget)
## form = RotateXYZGuiClass()
## #rotate = rotate_gui()
## form.setObjectName("kicadStepUp")
-##
+##
## if QtGui.QApplication.style().metaObject().className() == "QStyleSheetStyle":
## form.setStyleSheet('QPushButton {border-radius: 0px; padding: 1px 2px;}')
-
-
diff --git a/kicad_parser.py b/kicad_parser.py
index 7ec4472..9e99598 100644
--- a/kicad_parser.py
+++ b/kicad_parser.py
@@ -1,60 +1,68 @@
#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#****************************************************************************
+# ****************************************************************************
# maui full integration of fcad_pcb from @realthunder commit 121 #maui
## from __future__ import (absolute_import, division,
## print_function, unicode_literals)
-#from builtins import *
+# from builtins import *
# from future.utils import iteritems
# from __future__ import (absolute_import, division,
# print_function, unicode_literals)
-#from builtins import *
+# from builtins import *
-from collections import defaultdict
-from math import sqrt, atan2, degrees, sin, cos, radians, pi, hypot
import traceback
+from collections import defaultdict
+from math import degrees
+
+import DraftGeomUtils
+import DraftVecUtils
import FreeCAD
import FreeCADGui
import Part
-from FreeCAD import Console,Vector,Placement,Rotation
-import DraftGeomUtils,DraftVecUtils
+from FreeCAD import Placement, Rotation, Vector
try:
import CAM
except:
import Path
+
CAM = Path
-import sys, os
+import os
+import sys
+
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
-#from . import KicadPCB,SexpList
+# from . import KicadPCB,SexpList
# maui
-import fcad_parser
-from fcad_parser import KicadPCB,SexpList,SexpParser,parseSexp
-#from .fcad_parser import KicadPCB,SexpList
-#from .kicad_parser import unquote
-from fcad_parser import unquote #maui
+# from .fcad_parser import KicadPCB,SexpList
+# from .kicad_parser import unquote
+import contextlib
+from fcad_parser import (
+ KicadPCB,
+ SexpList,
+ parseSexp,
+ unquote, # maui
+)
# from kicadStepUptools import KicadPCB,SexpList
-__kicad_parser_version__ = '2.3.6'
+__kicad_parser_version__ = "2.3.6"
# https://github.com/realthunder/fcad_pcb/issues/20#issuecomment-586042341
-# FreeCAD.Console.PrintLog('kicad_parser_version '+__kicad_parser_version__+'\n') # maui
+# FreeCAD.Console.PrintLog('kicad_parser_version '+__kicad_parser_version__+'\n') # maui
# print('kicad_parser_version '+__kicad_parser_version__)
# maui
-PY3 = sys.version_info[0] == 3
-if PY3:
- string_types = str,
-else:
- string_types = basestring,
+PY3 = sys.version_info[0] >= 3
+string_types = (str,) if PY3 else (basestring,)
+
def _disableElementMapping(_):
pass
-disableTopoNaming = getattr(Part, 'disableElementMapping', _disableElementMapping)
+
+disableTopoNaming = getattr(Part, "disableElementMapping", _disableElementMapping)
+
def addObject(doc, tp, name):
obj = doc.addObject(tp, name)
@@ -66,99 +74,103 @@ def addObject(doc, tp, name):
pass
return obj
+
def updateGui():
- try:
+ with contextlib.suppress(Exception):
FreeCADGui.updateGui()
- except Exception:
- pass
+
class FCADLogger:
def __init__(self, tag):
self.tag = tag
- self.levels = { 'error':0, 'warning':1, 'info':2,
- 'log':3, 'trace':4 }
+ self.levels = {"error": 0, "warning": 1, "info": 2, "log": 3, "trace": 4}
- def _isEnabledFor(self,level):
+ def _isEnabledFor(self, level):
return FreeCAD.getLogLevel(self.tag) >= level
- def isEnabledFor(self,level):
+ def isEnabledFor(self, level):
return self._isEnabledFor(self.levels[level])
- def trace(self,msg):
+ def trace(self, msg):
if self._isEnabledFor(4):
- FreeCAD.Console.PrintLog(msg+'\n')
+ FreeCAD.Console.PrintLog(msg + "\n")
updateGui()
- def log(self,msg):
+ def log(self, msg):
if self._isEnabledFor(3):
- FreeCAD.Console.PrintLog(msg+'\n')
+ FreeCAD.Console.PrintLog(msg + "\n")
updateGui()
- def info(self,msg):
+ def info(self, msg):
if self._isEnabledFor(2):
- FreeCAD.Console.PrintMessage(msg+'\n')
+ FreeCAD.Console.PrintMessage(msg + "\n")
updateGui()
- def warning(self,msg):
+ def warning(self, msg):
if self._isEnabledFor(1):
- FreeCAD.Console.PrintWarning(msg+'\n')
+ FreeCAD.Console.PrintWarning(msg + "\n")
updateGui()
- def error(self,msg):
+ def error(self, msg):
if self._isEnabledFor(0):
- FreeCAD.Console.PrintError(msg+'\n')
+ FreeCAD.Console.PrintError(msg + "\n")
updateGui()
-logger = FCADLogger('fcad_pcb')
+
+logger = FCADLogger("fcad_pcb")
+
def getActiveDoc():
if FreeCAD.ActiveDocument is None:
- return FreeCAD.newDocument('kicad_fcad')
+ return FreeCAD.newDocument("kicad_fcad")
return FreeCAD.ActiveDocument
+
def fitView():
- try:
+ with contextlib.suppress(Exception):
FreeCADGui.ActiveDocument.ActiveView.fitAll()
- except Exception:
- pass
+
def isZero(f):
- return round(f,DraftGeomUtils.precision())==0
+ return round(f, DraftGeomUtils.precision()) == 0
+
def makeColor(*color):
- if len(color)==1:
- if isinstance(color[0],string_types):
- color = int(color[0],0)
- else:
- color = color[0]
- r = float((color>>24)&0xFF)
- g = float((color>>16)&0xFF)
- b = float((color>>8)&0xFF)
+ if len(color) == 1:
+ color = int(color[0], 0) if isinstance(color[0], string_types) else color[0]
+ r = float((color >> 24) & 0xFF)
+ g = float((color >> 16) & 0xFF)
+ b = float((color >> 8) & 0xFF)
else:
- r,g,b = color
- return (r/255.0,g/255.0,b/255.0)
+ r, g, b = color
+ return (r / 255.0, g / 255.0, b / 255.0)
+
def makeVect(l):
- return Vector(l[0],-l[1],0)
+ return Vector(l[0], -l[1], 0)
+
def getAt(sexp):
- at = getattr(sexp, 'at', None)
+ at = getattr(sexp, "at", None)
if not at:
- return Vector(0,0,0),0
+ return Vector(0, 0, 0), 0
v = makeVect(at)
- return (v,0) if len(at)==2 else (v,at[2])
+ return (v, 0) if len(at) == 2 else (v, at[2])
+
+
+def product(v1, v2):
+ return Vector(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z)
-def product(v1,v2):
- return Vector(v1.x*v2.x,v1.y*v2.y,v1.z*v2.z)
-def make_rect(size,params=None):
+def make_rect(size, params=None):
_ = params
- return Part.makePolygon([product(size,Vector(*v))
- for v in ((-0.5,-0.5),(0.5,-0.5),(0.5,0.5),(-0.5,0.5),(-0.5,-0.5))])
+ return Part.makePolygon(
+ [product(size, Vector(*v)) for v in ((-0.5, -0.5), (0.5, -0.5), (0.5, 0.5), (-0.5, 0.5), (-0.5, -0.5))],
+ )
-def make_trapezoid(size,params):
- pts = [product(size,Vector(*v)) \
- for v in ((-0.5,0.5),(-0.5,-0.5),(0.5,-0.5),(0.5,0.5))]
+
+def make_trapezoid(size, params):
+ pts = [product(size, Vector(*v)) for v in ((-0.5, 0.5), (-0.5, -0.5), (0.5, -0.5), (0.5, 0.5))]
try:
delta = params.rect_delta[0]
if delta:
@@ -172,152 +184,157 @@ def make_trapezoid(size,params):
length = size[0]
if delta <= -length:
collapse = 1
- delta = -length;
+ delta = -length
elif delta >= length:
collapse = -1
delta = length
else:
collapse = 0
- pts[0][idx] += delta*0.5
- pts[1][idx] -= delta*0.5
- pts[2][idx] += delta*0.5
- pts[3][idx] -= delta*0.5
+ pts[0][idx] += delta * 0.5
+ pts[1][idx] -= delta * 0.5
+ pts[2][idx] += delta * 0.5
+ pts[3][idx] -= delta * 0.5
if collapse:
del pts[collapse]
except Exception:
- logger.warning('trapezoid pad has no rect_delta')
+ logger.warning("trapezoid pad has no rect_delta")
pts.append(pts[0])
return Part.makePolygon(pts)
-def make_circle(size,params=None):
+
+def make_circle(size, params=None):
_ = params
- return Part.Wire(Part.makeCircle(size.x*0.5))
+ return Part.Wire(Part.makeCircle(size.x * 0.5))
+
-def make_oval(size,params=None):
+def make_oval(size, params=None):
_ = params
if size.x == size.y:
return make_circle(size)
if size.x < size.y:
- r = size.x*0.5
+ r = size.x * 0.5
size.y -= size.x
- s = ((0,0.5),(-0.5,0.5),(-0.5,-0.5),(0,-0.5),(0.5,-0.5),(0.5,0.5))
- a = (0,180,180,360)
+ s = ((0, 0.5), (-0.5, 0.5), (-0.5, -0.5), (0, -0.5), (0.5, -0.5), (0.5, 0.5))
+ a = (0, 180, 180, 360)
else:
- r = size.y*0.5
+ r = size.y * 0.5
size.x -= size.y
- s = ((-0.5,0),(-0.5,-0.5),(0.5,-0.5),(0.5,0),(0.5,0.5),(-0.5,0.5))
- a = (90,270,-90,-270)
- pts = [product(size,Vector(*v)) for v in s]
- return Part.Wire([
- Part.makeCircle(r,pts[0],Vector(0,0,1),a[0],a[1]),
- Part.makeLine(pts[1],pts[2]),
- Part.makeCircle(r,pts[3],Vector(0,0,1),a[2],a[3]),
- Part.makeLine(pts[4],pts[5])])
-
-def make_roundrect(size,params):
+ s = ((-0.5, 0), (-0.5, -0.5), (0.5, -0.5), (0.5, 0), (0.5, 0.5), (-0.5, 0.5))
+ a = (90, 270, -90, -270)
+ pts = [product(size, Vector(*v)) for v in s]
+ return Part.Wire(
+ [
+ Part.makeCircle(r, pts[0], Vector(0, 0, 1), a[0], a[1]),
+ Part.makeLine(pts[1], pts[2]),
+ Part.makeCircle(r, pts[3], Vector(0, 0, 1), a[2], a[3]),
+ Part.makeLine(pts[4], pts[5]),
+ ],
+ )
+
+
+def make_roundrect(size, params):
rratio = 0.25
try:
rratio = params.roundrect_rratio
if rratio > 0.5:
return make_oval(size)
except Exception:
- logger.warning('round rect pad has no rratio')
+ logger.warning("round rect pad has no rratio")
length = min(size.x, size.y)
- r = length*rratio
- n = Vector(0,0,1)
- sx = size.x*0.5
- sy = size.y*0.5
+ r = length * rratio
+ n = Vector(0, 0, 1)
+ sx = size.x * 0.5
+ sy = size.y * 0.5
- rounds = [(r,False)]*4
+ rounds = [(r, False)] * 4
- if 'chamfer_ratio' in params and 'chamfer' in params:
+ if "chamfer_ratio" in params and "chamfer" in params:
ratio = params.chamfer_ratio
if ratio < 0.0:
ratio = 0.0
elif ratio > 0.5:
ratio = 0.5
- for i,corner in enumerate(('top_right',
- 'top_left',
- 'bottom_left',
- 'bottom_right')):
+ for i, corner in enumerate(("top_right", "top_left", "bottom_left", "bottom_right")):
if corner in params.chamfer:
- rounds[i] = (ratio*length,True)
+ rounds[i] = (ratio * length, True)
edges = []
- r,chamfer = rounds[0]
- pstart = Vector(sx,sy-r)
+ r, chamfer = rounds[0]
+ pstart = Vector(sx, sy - r)
pt = pstart
- pnext = Vector(sx-r,sy)
+ pnext = Vector(sx - r, sy)
if r:
if not chamfer:
- edges.append(Part.makeCircle(r,Vector(sx-r,sy-r),n,0,90))
+ edges.append(Part.makeCircle(r, Vector(sx - r, sy - r), n, 0, 90))
else:
edges.append(Part.makeLine(pt, pnext))
- r,chamfer = rounds[1]
+ r, chamfer = rounds[1]
pt = pnext
- pnext = Vector(r-sx,sy)
+ pnext = Vector(r - sx, sy)
if pt != pnext:
- edges.append(Part.makeLine(pt,pnext))
+ edges.append(Part.makeLine(pt, pnext))
pt = pnext
- pnext = Vector(-sx,sy-r)
+ pnext = Vector(-sx, sy - r)
if r:
if not chamfer:
- edges.append(Part.makeCircle(r,Vector(r-sx,sy-r),n,90,180))
+ edges.append(Part.makeCircle(r, Vector(r - sx, sy - r), n, 90, 180))
else:
- edges.append(Part.makeLine(pt,pnext))
+ edges.append(Part.makeLine(pt, pnext))
- r,chamfer = rounds[2]
+ r, chamfer = rounds[2]
pt = pnext
- pnext = Vector(-sx,r-sy)
+ pnext = Vector(-sx, r - sy)
if pt != pnext:
- edges.append(Part.makeLine(pt,pnext))
+ edges.append(Part.makeLine(pt, pnext))
pt = pnext
- pnext = Vector(r-sx,-sy)
+ pnext = Vector(r - sx, -sy)
if r:
if not chamfer:
- edges.append(Part.makeCircle(r,Vector(r-sx,r-sy),n,180,270))
+ edges.append(Part.makeCircle(r, Vector(r - sx, r - sy), n, 180, 270))
else:
- edges.append(Part.makeLine(pt,pnext))
+ edges.append(Part.makeLine(pt, pnext))
- r,chamfer = rounds[3]
+ r, chamfer = rounds[3]
pt = pnext
- pnext = Vector(sx-r,-sy)
+ pnext = Vector(sx - r, -sy)
if pt != pnext:
- edges.append(Part.makeLine(pt,pnext))
+ edges.append(Part.makeLine(pt, pnext))
pt = pnext
- pnext = Vector(sx,r-sy)
+ pnext = Vector(sx, r - sy)
if r:
if not chamfer:
- edges.append(Part.makeCircle(r,Vector(sx-r,r-sy),n,270,360))
+ edges.append(Part.makeCircle(r, Vector(sx - r, r - sy), n, 270, 360))
else:
- edges.append(Part.makeLine(pt,pnext))
+ edges.append(Part.makeLine(pt, pnext))
pt = pnext
if pt != pstart:
- edges.append(Part.makeLine(pt,pstart))
+ edges.append(Part.makeLine(pt, pstart))
return Part.Wire(edges)
-#maui
+
+# maui
def make_gr_poly(params):
- if hasattr(params.pts,"xy"): #try:
+ if hasattr(params.pts, "xy"): # try:
points = SexpList(params.pts.xy)
# close the polygon
points._append(params.pts.xy._get(0))
# KiCAD polygon runs in clockwise, but FreeCAD wants CCW, so must reverse.
return Part.makePolygon([makeVect(p) for p in reversed(points)])
- else: # hasattr(params.pts,"arc") #except:
- arcs = SexpList(params.pts.arc)
- return Part.makeCompound([make_gr_arc(arc) for arc in (arcs)])
-
+ # hasattr(params.pts,"arc") #except:
+ arcs = SexpList(params.pts.arc)
+ return Part.makeCompound([make_gr_arc(arc) for arc in (arcs)])
+
+
# maui
def make_fp_poly(params):
points = SexpList(params.pts.xy)
@@ -325,38 +342,49 @@ def make_fp_poly(params):
points._append(params.pts.xy._get(0))
# KiCAD polygon runs in clockwise, but FreeCAD wants CCW, so must reverse.
return Part.makePolygon([makeVect(p) for p in reversed(points)])
+
+
# maui
+
def make_gr_line(params):
- return Part.makeLine(makeVect(params.start),makeVect(params.end))
+ return Part.makeLine(makeVect(params.start), makeVect(params.end))
+
def make_gr_arc(params):
- if hasattr(params, 'angle'):
- return makeArc(makeVect(params.start),makeVect(params.end),params.angle)
- return Part.ArcOfCircle(makeVect(params.start),
- makeVect(params.mid),
- makeVect(params.end)).toShape()
+ if hasattr(params, "angle"):
+ return makeArc(makeVect(params.start), makeVect(params.end), params.angle)
+ return Part.ArcOfCircle(makeVect(params.start), makeVect(params.mid), makeVect(params.end)).toShape()
+
def make_gr_curve(params):
return makeCurve([makeVect(p) for p in SexpList(params.pts.xy)])
+
def make_gr_circle(params, width=0):
center = makeVect(params.center)
end = makeVect(params.end)
r = center.distanceToPoint(end)
- if not width or r <= width*0.5:
- return Part.makeCircle(r+width*0.5, center)
- return Part.makeCompound([Part.Wire(Part.makeCircle(r+width*0.5,center)),
- Part.Wire(Part.makeCircle(r-width*0.5,center,Vector(0,0,-1)))])
+ if not width or r <= width * 0.5:
+ return Part.makeCircle(r + width * 0.5, center)
+ return Part.makeCompound(
+ [
+ Part.Wire(Part.makeCircle(r + width * 0.5, center)),
+ Part.Wire(Part.makeCircle(r - width * 0.5, center, Vector(0, 0, -1))),
+ ],
+ )
+
+
# maui
def make_gr_circle_outl(params, width=0):
center = makeVect(params.center)
end = makeVect(params.end)
r = center.distanceToPoint(end)
- if not width or r <= width*0.5:
- return Part.makeCircle(r+width*0.5, center)
- return [Part.makeCircle(r+width*0.5, center), Part.makeCircle(r-width*0.5,center)]
-
+ if not width or r <= width * 0.5:
+ return Part.makeCircle(r + width * 0.5, center)
+ return [Part.makeCircle(r + width * 0.5, center), Part.makeCircle(r - width * 0.5, center)]
+
+
# def make_gr_circle_outl(params, width=0):
# center = makeVect(params.center)
# end = makeVect(params.end)
@@ -370,72 +398,78 @@ def make_gr_circle_outl(params, width=0):
# # Part.Wire(Part.makeCircle(r-width*0.5,center,Vector(0,0,-1)))])
# maui
+
def make_gr_rect(params):
start = makeVect(params.start)
end = makeVect(params.end)
return Part.makePolygon([start, Vector(start.x, end.y), end, Vector(end.x, start.y), start])
+
def makePrimitve(key, params):
for param in SexpList(params):
try:
- width = getattr(param,'width',0)
- if width and key == 'gr_circle':
+ width = getattr(param, "width", 0)
+ if width and key == "gr_circle":
return make_gr_circle(param, width), 0
- else:
- make_shape = globals()['make_{}'.format(key)]
- #if key == 'gr_poly':
- # Part.show(Part.Face(make_fp_poly(params)))
- return make_shape(param), width
+ make_shape = globals()[f"make_{key}"]
+ # if key == 'gr_poly':
+ # Part.show(Part.Face(make_fp_poly(params)))
+ return make_shape(param), width
except KeyError:
- logger.warning('Unknown primitive {} in custom pad'.format(key))
+ logger.warning(f"Unknown primitive {key} in custom pad")
return None, None
- #try:
+ return None
+ # try:
# width = getattr(params,'width',0)
# if width and key == 'gr_circle':
# return make_gr_circle(params, width), 0
# else:
# make_shape = globals()['make_{}'.format(key)]
# return make_shape(params), width
- #except KeyError:
+ # except KeyError:
# logger.warning('Unknown primitive {} in custom pad'.format(key))
# return None, None
-def makeThickLine(p1,p2,width):
+
+def makeThickLine(p1, p2, width):
length = p1.distanceToPoint(p2)
- line = make_oval(Vector(length+2*width,2*width))
+ line = make_oval(Vector(length + 2 * width, 2 * width))
p = p2.sub(p1)
a = -degrees(DraftVecUtils.angle(p))
- line.translate(Vector(length*0.5))
- line.rotate(Vector(),Vector(0,0,1),a)
+ line.translate(Vector(length * 0.5))
+ line.rotate(Vector(), Vector(0, 0, 1), a)
line.translate(p1)
return line
-def makeArc(center,start,angle):
+
+def makeArc(center, start, angle):
p = start.sub(center)
r = p.Length
a = -degrees(DraftVecUtils.angle(p))
# NOTE: KiCAD pcb geometry runs in clockwise, while FreeCAD is CCW. So the
# resulting arc below is the reverse of what's specified in kicad_pcb
- if angle>0:
- arc = Part.makeCircle(r,center,Vector(0,0,1),a-angle,a)
- arc.reverse();
+ if angle > 0:
+ arc = Part.makeCircle(r, center, Vector(0, 0, 1), a - angle, a)
+ arc.reverse()
else:
- arc = Part.makeCircle(r,center,Vector(0,0,1),a,a-angle)
+ arc = Part.makeCircle(r, center, Vector(0, 0, 1), a, a - angle)
return arc
+
def makeCurve(poles):
return Part.BSplineCurve(poles).toShape()
+
def findWires(edges):
try:
return [Part.Wire(e) for e in Part.sortEdges(edges)]
except AttributeError:
- msg = 'Missing Part.sortEdges.'\
- 'You need newer FreeCAD (0.17 git 799c43d2)'
- logger.error(msg)
+ msg = "Missing Part.sortEdges.You need newer FreeCAD (0.17 git 799c43d2)"
+ logger.exception(msg)
raise AttributeError(msg)
-def getFaceCompound(shape,wire=False):
+
+def getFaceCompound(shape, wire=False):
objs = []
for f in shape.Faces:
selected = True
@@ -450,115 +484,119 @@ def getFaceCompound(shape,wire=False):
## TODO: FreeCAD curve.normalAt is not implemented
################################################################
# for e in f.Edges:
- # if isinstance(e.Curve,(Part.LineSegment,Part.Line)): continue
- # if not isZero(e.normalAt(Vector()).dot(Vector(0,0,1))):
- # selected = False
- # break
+ # if isinstance(e.Curve,(Part.LineSegment,Part.Line)): continue
+ # if not isZero(e.normalAt(Vector()).dot(Vector(0,0,1))):
+ # selected = False
+ # break
# if not selected: continue
if not wire:
objs.append(f)
continue
- for w in f.Wires:
- objs.append(w)
+ objs.extend(f.Wires)
if not objs:
- raise ValueError('null shape')
+ raise ValueError("null shape")
return Part.makeCompound(objs)
def unpack(obj):
if not obj:
- raise ValueError('null shape')
+ raise ValueError("null shape")
- if isinstance(obj,(list,tuple)) and len(obj)==1:
+ if isinstance(obj, (list, tuple)) and len(obj) == 1:
return obj[0]
return obj
-def getKicadPath(env=''):
- confpath = ''
+def getKicadPath(env=""):
+ confpath = ""
if env:
- confpath = os.path.expanduser(os.environ.get(env,''))
+ confpath = os.path.expanduser(os.environ.get(env, ""))
if not os.path.isdir(confpath):
- confpath=''
+ confpath = ""
if not confpath:
- if sys.platform == 'darwin':
- confpath = os.path.expanduser('~/Library/Preferences/kicad')
- elif sys.platform == 'win32':
- confpath = os.path.join(
- os.path.abspath(os.environ['APPDATA']),'kicad')
+ if sys.platform == "darwin":
+ confpath = os.path.expanduser("~/Library/Preferences/kicad")
+ elif sys.platform == "win32":
+ confpath = os.path.join(os.path.abspath(os.environ["APPDATA"]), "kicad")
else:
- confpath=os.path.expanduser('~/.config/kicad')
+ confpath = os.path.expanduser("~/.config/kicad")
import re
- kicad_common = os.path.join(confpath,'kicad_common')
+
+ kicad_common = os.path.join(confpath, "kicad_common")
if not os.path.isfile(kicad_common):
kicad_common += ".json"
if not os.path.isfile(kicad_common):
- logger.warning('cannot find kicad_common')
+ logger.warning("cannot find kicad_common")
return None
- with open(kicad_common,'r', encoding='utf-8') as f:
+ with open(kicad_common, encoding="utf-8") as f:
content = f.read()
- match = re.search(r'^\s*"*KISYS3DMOD"*\s*[:=]\s*([^\r\n]+)',content,re.MULTILINE)
+ match = re.search(r'^\s*"*KISYS3DMOD"*\s*[:=]\s*([^\r\n]+)', content, re.MULTILINE)
if not match:
- logger.warning('no KISYS3DMOD found')
+ logger.warning("no KISYS3DMOD found")
return None
return match.group(1).rstrip(' "')
+
_model_cache = {}
+
def clearModelCache():
_model_cache = {}
+
def recomputeObj(obj):
obj.recompute()
obj.purgeTouched()
+
def loadModel(filename):
mtime = None
try:
mtime = os.path.getmtime(filename)
obj = _model_cache[filename]
if obj[2] == mtime:
- logger.info('model cache hit');
+ logger.info("model cache hit")
return obj
- else:
- logger.info('model reload due to time stamp change');
+ logger.info("model reload due to time stamp change")
except KeyError:
pass
except OSError:
- return
+ return None
import ImportGui
+
doc = getActiveDoc()
if not os.path.isfile(filename):
- return
+ return None
count = len(doc.Objects)
dobjs = []
try:
- ImportGui.insert(filename,doc.Name)
+ ImportGui.insert(filename, doc.Name)
dobjs = doc.Objects[count:]
- obj = addObject(doc,'Part::Compound','tmp')
+ obj = addObject(doc, "Part::Compound", "tmp")
obj.Links = dobjs
recomputeObj(obj)
- dobjs = [obj]+dobjs
- obj = (obj.Shape.copy(),obj.ViewObject.DiffuseColor,mtime)
+ dobjs = [obj, *dobjs]
+ obj = (obj.Shape.copy(), obj.ViewObject.DiffuseColor, mtime)
_model_cache[filename] = obj
return obj
- except Exception as ex:
- logger.error('failed to load model: {}'.format(ex))
+ except Exception:
+ logger.exception("failed to load model")
finally:
for o in dobjs:
doc.removeObject(o.Name)
+
class KicadFcad:
- def __init__(self,filename=None,debug=False,**kwds):
+ def __init__(self, filename=None, debug=False, **kwds):
#############################################################
# Beginning of user customizable parameters during construction
- self.prefix = ''
- self.indent = ' '
+ self.prefix = ""
+ self.indent = " "
self.make_sketch = False
self.sketch_use_draft = False
self.sketch_radius_precision = -1
@@ -571,7 +609,7 @@ def __init__(self,filename=None,debug=False,**kwds):
self.merge_vias = not debug
self.merge_tracks = not debug
self.zone_merge_holes = not debug
- self.merge_pads = not debug # False # maui to evaluate for better pad results
+ self.merge_pads = not debug # False # maui to evaluate for better pad results
self.arc_fit_accuracy = 0.0005
self.layer_thickness = 0.01
self.copper_thickness = 0.05
@@ -588,38 +626,38 @@ def __init__(self,filename=None,debug=False,**kwds):
self.add_feature = True
self.part_path = None
- self.path_env = 'KICAD_CONFIG_HOME'
+ self.path_env = "KICAD_CONFIG_HOME"
self.hole_size_offset = 0.0001
self.pad_inflate = 0
self.zone_inflate = 0
self.nets = []
if filename is None:
- filename = '/home/thunder/pwr.kicad_pcb'
+ filename = "/home/thunder/pwr.kicad_pcb"
if not os.path.isfile(filename):
- raise ValueError("file not found");
+ raise ValueError("file not found")
self.filename = filename
self.colors = {
- 'board':makeColor("0x3A6629"),
- 'pad':{0:makeColor(219,188,126)}, # maui pads color
- 'zone':{0:makeColor(0,80,0)},
- 'track':{0:makeColor(0,120,0)},
- 'copper':{0:makeColor(200,117,51)},
- 'F.Cu':{0:makeColor(200,117,51)}, # maui start color
- 'B.Cu':{0:makeColor(200,117,51)},
- 'F.SilkS':{0:makeColor(0,0,255)},
- 'B.SilkS':{0:makeColor(0,0,255)},
- 'F.CrtYd':{0:makeColor(255,170,255)},
- 'B.CrtYd':{0:makeColor(255,170,255)},
- 'F.Fab':{0:makeColor(0,255,0)},
- 'B.Fab':{0:makeColor(0,255,0)},
- 'F.Adhes':{0:makeColor(0,127,255)},
- 'B.Adhes':{0:makeColor(127,0,255)},
- 'Edge.Cuts':{0:makeColor(255,0,0)},
- 'Margin':{0:makeColor(255,170,170)},
- 'holes':{0:makeColor(170,255,127)},
- 'NetTie':{0:makeColor(255,114,12)},
- 'Dwgs.User':{0:makeColor(188,188,188)}, # maui end color
- 'Cmts.User':{0:makeColor(0,170,255)}, # maui end color
+ "board": makeColor("0x3A6629"),
+ "pad": {0: makeColor(219, 188, 126)}, # maui pads color
+ "zone": {0: makeColor(0, 80, 0)},
+ "track": {0: makeColor(0, 120, 0)},
+ "copper": {0: makeColor(200, 117, 51)},
+ "F.Cu": {0: makeColor(200, 117, 51)}, # maui start color
+ "B.Cu": {0: makeColor(200, 117, 51)},
+ "F.SilkS": {0: makeColor(0, 0, 255)},
+ "B.SilkS": {0: makeColor(0, 0, 255)},
+ "F.CrtYd": {0: makeColor(255, 170, 255)},
+ "B.CrtYd": {0: makeColor(255, 170, 255)},
+ "F.Fab": {0: makeColor(0, 255, 0)},
+ "B.Fab": {0: makeColor(0, 255, 0)},
+ "F.Adhes": {0: makeColor(0, 127, 255)},
+ "B.Adhes": {0: makeColor(127, 0, 255)},
+ "Edge.Cuts": {0: makeColor(255, 0, 0)},
+ "Margin": {0: makeColor(255, 170, 170)},
+ "holes": {0: makeColor(170, 255, 127)},
+ "NetTie": {0: makeColor(255, 114, 12)},
+ "Dwgs.User": {0: makeColor(188, 188, 188)}, # maui end color
+ "Cmts.User": {0: makeColor(0, 170, 255)}, # maui end color
}
self.layer_type = 0
self.layer_match = None
@@ -627,20 +665,21 @@ def __init__(self,filename=None,debug=False,**kwds):
#############################################################
# checking user overridden parameters
- for key,value in kwds.items():
- if not hasattr(self,key):
- raise ValueError('unknown parameter "{}"'.format(key))
- setattr(self,key,value)
+ for key, value in kwds.items():
+ if not hasattr(self, key):
+ raise ValueError(f'unknown parameter "{key}"')
+ setattr(self, key, value)
if not self.part_path:
self.part_path = getKicadPath(self.path_env)
self.pcb = KicadPCB.load(self.filename, self.quote_no_parse)
- #print(str(self.pcb))
- if self.pcb._key == 'footprint':
- self.pcb._key = 'module'
- if self.pcb._key == 'module':
+ # print(str(self.pcb))
+ if self.pcb._key == "footprint":
+ self.pcb._key = "module"
+ if self.pcb._key == "module":
# this is a kicad_mod file, make it look like a kicad_pcb
- pcb = KicadPCB(parseSexp('''
+ pcb = KicadPCB(
+ parseSexp("""
(kicad_pcb
(general
(thickness 1.6) # maui
@@ -672,21 +711,20 @@ def __init__(self,filename=None,debug=False,**kwds):
(48 B.Fab user)
(49 F.Fab user)
)
- )'''))
+ )"""),
+ )
self.module = self.pcb
pcb.module._append(self.pcb)
- #print(str(self.pcb))
+ # print(str(self.pcb))
self.pcb = pcb
else:
self.module = None
if not self.board_thickness:
- try:
+ with contextlib.suppress(Exception):
self.board_thickness = self.pcb.general.thickness
- except Exception:
- pass
if not self.board_thickness:
- self.board_thickness = 1.6 # maui
+ self.board_thickness = 1.6 # maui
self._dielectric_layers = []
self._stackup_map = {}
@@ -694,10 +732,10 @@ def __init__(self,filename=None,debug=False,**kwds):
# stores layer name as read from the file, may contain quotes depending
# on kicad version
- self.layer_name = ''
+ self.layer_name = ""
# stores layer name without quote
- self.layer = ''
+ self.layer = ""
self.setLayer(self.layer_type)
@@ -705,49 +743,48 @@ def __init__(self,filename=None,debug=False,**kwds):
self.via_skip_hole = True
self._nets = set()
- self.net_names = dict()
- if 'net' in self.pcb:
+ self.net_names = {}
+ if "net" in self.pcb:
for n in self.pcb.net:
self.net_names[n[0]] = n[1]
self.setNetFilter(*self.nets)
- def findLayer(self,layer, deftype=None):
+ def findLayer(self, layer, deftype=None):
try:
layer = int(layer)
except:
for layer_type in self.pcb.layers:
name = self.pcb.layers[layer_type][0]
- if name==layer or unquote(name)==layer:
- return (int(layer_type),name)
+ if name == layer or unquote(name) == layer:
+ return (int(layer_type), name)
if deftype is not None:
return deftype, layer
- raise KeyError('layer {} not found'.format(layer))
+ raise KeyError(f"layer {layer} not found")
else:
if str(layer) not in self.pcb.layers:
if deftype is not None:
return deftype, str(layer)
- raise KeyError('layer {} not found'.format(layer))
+ raise KeyError(f"layer {layer} not found")
return (layer, self.pcb.layers[str(layer)][0])
- def setLayer(self,layer):
+ def setLayer(self, layer):
self.layer_type, self.layer_name = self.findLayer(layer)
self.layer = unquote(self.layer_name)
if self.layer_type <= 31:
- self.layer_match = '*.Cu'
+ self.layer_match = "*.Cu"
else:
- self.layer_match = '*.{}'.format(self.layer.split('.')[-1])
+ self.layer_match = "*.{}".format(self.layer.split(".")[-1])
def _copperLayers(self):
- coppers = [ (int(t),unquote(self.pcb.layers[t][0])) \
- for t in self.pcb.layers if int(t)<=31]
- coppers.sort(key=lambda x : x[0])
+ coppers = [(int(t), unquote(self.pcb.layers[t][0])) for t in self.pcb.layers if int(t) <= 31]
+ coppers.sort(key=lambda x: x[0])
return coppers
def _initStackUp(self):
if self.stackup is None:
- self._log('{}','kicad version='+str(self.pcb.version),level='info') # maui
+ self._log("{}", "kicad version=" + str(self.pcb.version), level="info") # maui
self.stackup = []
- stackup = getattr(getattr(self.pcb, 'setup', None), 'stackup', None)
+ stackup = getattr(getattr(self.pcb, "setup", None), "stackup", None)
if stackup:
try:
# If no stackup given by user, extract stack info from setup
@@ -755,8 +792,11 @@ def _initStackUp(self):
last_copper = 0.0
for layer in stackup.layer:
layer_type, _ = self.findLayer(layer[0], 99)
- t = getattr(layer, 'thickness',
- self.copper_thickness if layer_type<=32 else self.layer_thickness)
+ t = getattr(
+ layer,
+ "thickness",
+ self.copper_thickness if layer_type <= 32 else self.layer_thickness,
+ )
if layer_type <= 31:
last_copper = offset
# Some layer (e.g. dielectric) may have more than one
@@ -782,22 +822,22 @@ def _initStackUp(self):
# Right now, makeBoard() always assume it is at z = 0.
for entry in self.stackup:
entry[1] -= last_copper
- except Exception as e:# maui logging error and keeping kv5 compatibility
+ except Exception: # maui logging error and keeping kv5 compatibility
# raise
- # self._log('Failed parsing stackup info: {}', str(e), level='warning') # maui
- # traceback.print_exc() # maui
- error_message = traceback.format_exc() #maui
- self._log('{}',error_message,level='error') # maui
- pass # maui keeping kv5 compatibility
+ # self._log('Failed parsing stackup info: {}', str(e), level='warning') # maui
+ # traceback.print_exc() # maui
+ error_message = traceback.format_exc() # maui
+ self._log("{}", error_message, level="error") # maui
+ # maui keeping kv5 compatibility
else:
- self._log('{}','kicad v5 stack missing',level='warning') # maui end
+ self._log("{}", "kicad v5 stack missing", level="warning") # maui end
board_thickness = 0.0
accumulate = None
for item in self.stackup:
layer, name = self.findLayer(item[0], 99)
self._stackup_map[unquote(name)] = item
thickness = item[2]
- if layer <= 31: # is copper layer
+ if layer <= 31: # is copper layer
if accumulate is not None:
# counting intermediate layer(s) thickness
board_thickness += accumulate
@@ -811,10 +851,9 @@ def _initStackUp(self):
# only respect stackup if all copper layers are specified
coppers = self._copperLayers()
if self.stackup:
- for _,name in coppers:
+ for _, name in coppers:
if unquote(name) not in self._stackup_map:
- self._log('stackup info ignored because copper layer {} is not found',
- name, level='warning')
+ self._log("stackup info ignored because copper layer {} is not found", name, level="warning")
self.stackup = []
self._stackup_map = {}
break
@@ -826,9 +865,9 @@ def _initStackUp(self):
name = coppers[0][1]
self._stackup_map[name] = [name, 0, self.copper_thickness]
else:
- step = (self.board_thickness + self.copper_thickness) / (len(coppers)-1)
+ step = (self.board_thickness + self.copper_thickness) / (len(coppers) - 1)
offset = self.board_thickness
- for _,name in coppers:
+ for _, name in coppers:
self._stackup_map[name] = [name, offset, self.copper_thickness]
offset -= step
@@ -843,7 +882,7 @@ def _initStackUp(self):
def layerOffsets(self, thickness=None):
coppers = self._copperLayers()
- offsets = dict()
+ offsets = {}
if not thickness:
for _, name in coppers:
offsets[name] = self._stackup_map[name][1]
@@ -852,16 +891,16 @@ def layerOffsets(self, thickness=None):
if len(coppers) == 1:
offsets[coppers[0][1]] = 0
return offsets
- step = thickness / (len(coppers)-1)
+ step = thickness / (len(coppers) - 1)
offset = 0.0
- for _,name in coppers:
+ for _, name in coppers:
offsets[name] = offset
offset += step
return offsets
- def setNetFilter(self,*nets):
+ def setNetFilter(self, *nets):
self._nets.clear()
- ndict = dict()
+ ndict = {}
nset = set()
for n in self.pcb.net:
ndict[n[1]] = n[0]
@@ -879,95 +918,95 @@ def setNetFilter(self,*nets):
continue
except Exception:
pass
- logger.error('net {} not found'.format(n))
+ logger.error(f"net {n} not found")
- def getNet(self,p):
+ def getNet(self, p):
n = p.net
- return n if not isinstance(n,list) else n[0]
+ return n if not isinstance(n, list) else n[0]
- def filterNets(self,p):
+ def filterNets(self, p):
try:
return self._nets and self.getNet(p) not in self._nets
except Exception:
return bool(self._nets)
- def filterLayer(self,p):
+ def filterLayer(self, p):
layers = []
- l = getattr(p, 'layers', [])
- if unquote(l) == 'F&B.Cu': # maui
- layers.append('F.Cu')
- layers.append('B.Cu')
+ l = getattr(p, "layers", [])
+ if unquote(l) == "F&B.Cu": # maui
+ layers.append("F.Cu")
+ layers.append("B.Cu")
else:
layers = [unquote(s) for s in l]
- if hasattr(p, 'layer'):
+ if hasattr(p, "layer"):
layers.append(unquote(p.layer))
if not layers:
- self._log('no layers specified', level='warning')
+ self._log("no layers specified", level="warning")
return True
- if self.layer not in layers \
- and self.layer_match not in layers \
- and '*' not in layers:
- self._log('skip layer {}, {}, {}',
- self.layer, self.layer_match, layers, level='trace')
+ if self.layer not in layers and self.layer_match not in layers and "*" not in layers:
+ self._log("skip layer {}, {}, {}", self.layer, self.layer_match, layers, level="trace")
return True
+ return None
- def netName(self,p):
+ def netName(self, p):
try:
return unquote(self.net_names[self.getNet(p)])
except Exception:
- return 'net?'
+ return "net?"
- def _log(self,msg,*arg,**kargs):
- level = 'info'
- if kargs:
- if 'level' in kargs:
- level = kargs['level']
+ def _log(self, msg, *arg, **kargs):
+ level = "info"
+ if kargs and "level" in kargs:
+ level = kargs["level"]
if logger.isEnabledFor(level):
- getattr(logger,level)('{}{}'.format(self.prefix,msg.format(*arg)))
+ getattr(logger, level)(f"{self.prefix}{msg.format(*arg)}")
-
- def _pushLog(self,msg=None,*arg,**kargs):
+ def _pushLog(self, msg=None, *arg, **kargs):
if msg:
- self._log(msg,*arg,**kargs)
- if 'prefix' in kargs:
- prefix = kargs['prefix']
+ self._log(msg, *arg, **kargs)
+ if "prefix" in kargs:
+ prefix = kargs["prefix"]
if prefix is not None:
self.prefix = prefix
self.prefix += self.indent
-
- def _popLog(self,msg=None,*arg,**kargs):
- self.prefix = self.prefix[:-len(self.indent)]
+ def _popLog(self, msg=None, *arg, **kargs):
+ self.prefix = self.prefix[: -len(self.indent)]
if msg:
- self._log(msg,*arg,**kargs)
+ self._log(msg, *arg, **kargs)
- def _makeLabel(self,obj,label):
+ def _makeLabel(self, obj, label):
if self.layer:
- obj.Label = '{}#{}'.format(obj.Name,self.layer)
+ obj.Label = f"{obj.Name}#{self.layer}"
if label is not None:
- obj.Label += '#{}'.format(label)
+ obj.Label += f"#{label}"
- def _makeObject(self,otype,name,
- label=None,links=None,shape=None):
+ def _makeObject(self, otype, name, label=None, links=None, shape=None):
doc = getActiveDoc()
- obj = addObject(doc,otype,name)
- self._makeLabel(obj,label)
+ obj = addObject(doc, otype, name)
+ self._makeLabel(obj, label)
if links is not None:
- setattr(obj,links,shape)
- for s in shape if isinstance(shape,(list,tuple)) else (shape,):
- if hasattr(s,'ViewObject'):
+ setattr(obj, links, shape)
+ for s in shape if isinstance(shape, (list, tuple)) else (shape,):
+ if hasattr(s, "ViewObject"):
s.ViewObject.Visibility = False
- if hasattr(obj,'recompute'):
+ if hasattr(obj, "recompute"):
recomputeObj(obj)
return obj
- def _makeSketch(self,objs,name,label=None):
+ def _makeSketch(self, objs, name, label=None):
if self.sketch_use_draft:
import Draft
+
getActiveDoc()
- nobj = Draft.makeSketch(objs,name=name,autoconstraints=True,
- delete=True,radiusPrecision=self.sketch_radius_precision)
- self._makeLabel(nobj,label)
+ nobj = Draft.makeSketch(
+ objs,
+ name=name,
+ autoconstraints=True,
+ delete=True,
+ radiusPrecision=self.sketch_radius_precision,
+ )
+ self._makeLabel(nobj, label)
return nobj
from Sketcher import Constraint
@@ -977,8 +1016,8 @@ def _makeSketch(self,objs,name,label=None):
doc = getActiveDoc()
- nobj = addObject(doc,"Sketcher::SketchObject", '{}_sketch'.format(name))
- self._makeLabel(nobj,label)
+ nobj = addObject(doc, "Sketcher::SketchObject", f"{name}_sketch")
+ self._makeLabel(nobj, label)
nobj.ViewObject.Autoconstraints = False
radiuses = {}
@@ -986,79 +1025,68 @@ def _makeSketch(self,objs,name,label=None):
def addRadiusConstraint(edge):
try:
- if self.sketch_radius_precision<0:
+ if self.sketch_radius_precision < 0:
return
- if self.sketch_radius_precision==0:
- constraints.append(Constraint('Radius',
- nobj.GeometryCount-1, edge.Curve.Radius))
+ if self.sketch_radius_precision == 0:
+ constraints.append(Constraint("Radius", nobj.GeometryCount - 1, edge.Curve.Radius))
return
- r = round(edge.Curve.Radius,self.sketch_radius_precision)
- constraints.append(Constraint('Equal',
- radiuses[r], nobj.GeometryCount-1))
+ r = round(edge.Curve.Radius, self.sketch_radius_precision)
+ constraints.append(Constraint("Equal", radiuses[r], nobj.GeometryCount - 1))
except KeyError:
- radiuses[r] = nobj.GeometryCount-1
- constraints.append(Constraint('Radius',nobj.GeometryCount-1,r))
+ radiuses[r] = nobj.GeometryCount - 1
+ constraints.append(Constraint("Radius", nobj.GeometryCount - 1, r))
except AttributeError:
pass
- for obj in objs if isinstance(objs,(list,tuple)) else (objs,):
- if isinstance(obj,Part.Shape):
- shape = obj
- else:
- shape = obj.Shape
+ for obj in objs if isinstance(objs, (list, tuple)) else (objs,):
+ shape = obj if isinstance(obj, Part.Shape) else obj.Shape
norm = DraftGeomUtils.getNormal(shape)
if not self.sketch_constraint:
for wire in shape.Wires:
for edge in wire.OrderedEdges:
- nobj.addGeometry(DraftGeomUtils.orientEdge(
- edge,norm,make_arc=True))
+ nobj.addGeometry(DraftGeomUtils.orientEdge(edge, norm, make_arc=True))
continue
for wire in shape.Wires:
last_count = nobj.GeometryCount
edges = wire.OrderedEdges
for edge in edges:
- nobj.addGeometry(DraftGeomUtils.orientEdge(
- edge,norm,make_arc=True))
+ nobj.addGeometry(DraftGeomUtils.orientEdge(edge, norm, make_arc=True))
addRadiusConstraint(edge)
- for i,g in enumerate(nobj.Geometry[last_count:]):
+ for i, g in enumerate(nobj.Geometry[last_count:]):
if edges[i].Closed:
continue
- seg = last_count+i
+ seg = last_count + i
if self.sketch_align_constraint:
- if DraftGeomUtils.isAligned(g,"x"):
- constraints.append(Constraint("Vertical",seg))
- elif DraftGeomUtils.isAligned(g,"y"):
- constraints.append(Constraint("Horizontal",seg))
+ if DraftGeomUtils.isAligned(g, "x"):
+ constraints.append(Constraint("Vertical", seg))
+ elif DraftGeomUtils.isAligned(g, "y"):
+ constraints.append(Constraint("Horizontal", seg))
- if seg == nobj.GeometryCount-1:
+ if seg == nobj.GeometryCount - 1:
if not wire.isClosed():
break
g2 = nobj.Geometry[last_count]
seg2 = last_count
else:
- seg2 = seg+1
+ seg2 = seg + 1
g2 = nobj.Geometry[seg2]
end1 = g.value(g.LastParameter)
start2 = g2.value(g2.FirstParameter)
- if DraftVecUtils.equals(end1,start2) :
- constraints.append(Constraint(
- "Coincident",seg,EndPoint,seg2,StartPoint))
+ if DraftVecUtils.equals(end1, start2):
+ constraints.append(Constraint("Coincident", seg, EndPoint, seg2, StartPoint))
continue
end2 = g2.value(g2.LastParameter)
start1 = g.value(g.FirstParameter)
- if DraftVecUtils.equals(end2,start1):
- constraints.append(Constraint(
- "Coincident",seg,StartPoint,seg2,EndPoint))
- elif DraftVecUtils.equals(start1,start2):
- constraints.append(Constraint(
- "Coincident",seg,StartPoint,seg2,StartPoint))
- elif DraftVecUtils.equals(end1,end2):
- constraints.append(Constraint(
- "Coincident",seg,EndPoint,seg2,EndPoint))
+ if DraftVecUtils.equals(end2, start1):
+ constraints.append(Constraint("Coincident", seg, StartPoint, seg2, EndPoint))
+ elif DraftVecUtils.equals(start1, start2):
+ constraints.append(Constraint("Coincident", seg, StartPoint, seg2, StartPoint))
+ elif DraftVecUtils.equals(end1, end2):
+ constraints.append(Constraint("Coincident", seg, EndPoint, seg2, EndPoint))
if obj.isDerivedFrom("Part::Feature"):
objs = [obj]
@@ -1071,28 +1099,23 @@ def addRadiusConstraint(edge):
recomputeObj(nobj)
return nobj
- def _makeCompound(self,obj,name,label=None,fit_arcs=False,
- fuse=False,add_feature=False,force=False):
+ def _makeCompound(self, obj, name, label=None, fit_arcs=False, fuse=False, add_feature=False, force=False):
obj = unpack(obj)
- if not isinstance(obj,(list,tuple)):
- if not force and (
- not fuse or obj.TypeId=='Path::FeatureArea'):
+ if not isinstance(obj, (list, tuple)):
+ if not force and (not fuse or obj.TypeId == "Path::FeatureArea"):
return obj
obj = [obj]
if fuse:
- return self._makeArea(obj,name,label=label,fit_arcs=fit_arcs)
+ return self._makeArea(obj, name, label=label, fit_arcs=fit_arcs)
if add_feature or self.add_feature:
- return self._makeObject('Part::Compound',
- '{}_combo'.format(name),label,'Links',obj)
+ return self._makeObject("Part::Compound", f"{name}_combo", label, "Links", obj)
return Part.makeCompound(obj)
-
- def _makeArea(self,obj,name,offset=0,op=0,fill=None,label=None,
- force=False,fit_arcs=False,reorient=False):
+ def _makeArea(self, obj, name, offset=0, op=0, fill=None, label=None, force=False, fit_arcs=False, reorient=False):
if fill is None:
fill = 2
elif fill:
@@ -1100,21 +1123,21 @@ def _makeArea(self,obj,name,offset=0,op=0,fill=None,label=None,
else:
fill = 0
- if not isinstance(obj,(list,tuple)):
+ if not isinstance(obj, (list, tuple)):
obj = (obj,)
if self.add_feature and name:
-
- if not force and obj[0].TypeId == 'Path::FeatureArea' and (
- obj[0].Operation == op or len(obj[0].Sources)==1) and \
- obj[0].Fill == fill:
-
+ if (
+ not force
+ and obj[0].TypeId == "Path::FeatureArea"
+ and (obj[0].Operation == op or len(obj[0].Sources) == 1)
+ and obj[0].Fill == fill
+ ):
ret = obj[0]
if len(obj) > 1:
ret.Sources = list(ret.Sources) + list(obj[1:])
else:
- ret = self._makeObject('Path::FeatureArea',
- '{}_area'.format(name),label)
+ ret = self._makeObject("Path::FeatureArea", f"{name}_area", label)
ret.Accuracy = self.arc_fit_accuracy
ret.Sources = obj
ret.Operation = op
@@ -1129,30 +1152,31 @@ def _makeArea(self,obj,name,offset=0,op=0,fill=None,label=None,
recomputeObj(ret)
else:
- try: # maui CAM.Area is missing from F1.0 ahead
- ret = CAM.Area(Fill=fill,
- FitArcs=fit_arcs,
- Coplanar=0,
- Reorient=reorient,
- Accuracy=self.arc_fit_accuracy,
- Offset=offset)
+ try: # maui CAM.Area is missing from F1.0 ahead
+ ret = CAM.Area(
+ Fill=fill,
+ FitArcs=fit_arcs,
+ Coplanar=0,
+ Reorient=reorient,
+ Accuracy=self.arc_fit_accuracy,
+ Offset=offset,
+ )
ret.setPlane(self.work_plane)
for o in obj:
- ret.add(o,op=op)
+ ret.add(o, op=op)
ret = ret.getShape()
- except: # maui emulating CAM.Area functions
- objn=[]
- name='nm'
+ except: # maui emulating CAM.Area functions
+ objn = []
+ name = "nm"
for o in obj:
print(o)
Part.show(o)
# f = Part.Face(o)
# Part.show(f)
- ao=FreeCAD.ActiveDocument.ActiveObject
+ ao = FreeCAD.ActiveDocument.ActiveObject
recomputeObj(ao)
objn.append(ao)
- ret = self._makeObject('Path::FeatureArea',
- '{}_area'.format(name),label)
+ ret = self._makeObject("Path::FeatureArea", f"{name}_area", label)
ret.Accuracy = self.arc_fit_accuracy
print(objn)
ret.Sources = objn
@@ -1166,100 +1190,89 @@ def _makeArea(self,obj,name,offset=0,op=0,fill=None,label=None,
for o in objn:
o.ViewObject.Visibility = False
recomputeObj(ret)
- #retf=Part.Face(ret.Shape.Wires)
+ # retf=Part.Face(ret.Shape.Wires)
# retf=ret.Shape.Wires
- to_del=[]
- for o in objn:
- to_del.append(o)
- #to_del.append(ret)
+ to_del = list(objn)
+ # to_del.append(ret)
for o in to_del:
- #print(o)
+ # print(o)
FreeCAD.ActiveDocument.removeObject(o.Name)
- ret1=ret.Shape
+ ret1 = ret.Shape
FreeCAD.ActiveDocument.removeObject(ret.Name)
- ret=ret1
+ ret = ret1
return ret
-
- def _makeWires(self,obj,name,offset=0,fill=False,label=None, fit_arcs=False):
+ def _makeWires(self, obj, name, offset=0, fill=False, label=None, fit_arcs=False):
if self.add_feature and name:
if self.make_sketch:
- obj = self._makeSketch(obj,name,label)
- elif isinstance(obj,Part.Shape):
- obj = self._makeObject('Part::Feature', '{}_wire'.format(name),
- label,'Shape',obj)
- elif isinstance(obj,(list,tuple)):
+ obj = self._makeSketch(obj, name, label)
+ elif isinstance(obj, Part.Shape):
+ obj = self._makeObject("Part::Feature", f"{name}_wire", label, "Shape", obj)
+ elif isinstance(obj, (list, tuple)):
objs = []
comp = []
for o in obj:
- if isinstance(o,Part.Shape):
+ if isinstance(o, Part.Shape):
comp.append(o)
else:
objs.append(o)
if comp:
comp = Part.makeCompound(comp)
- objs.append(self._makeObject('Part::Feature',
- '{}_wire'.format(name),label,'Shape',comp))
+ objs.append(self._makeObject("Part::Feature", f"{name}_wire", label, "Shape", comp))
obj = objs
if fill or offset:
- return self._makeArea(obj,name,offset=offset,fill=fill,
- fit_arcs=fit_arcs,label=label)
- else:
- return self._makeCompound(obj,name,label=label)
+ return self._makeArea(obj, name, offset=offset, fill=fill, fit_arcs=fit_arcs, label=label)
+ return self._makeCompound(obj, name, label=label)
+ def _makeSolid(self, obj, name, height, label=None, fit_arcs=True):
- def _makeSolid(self,obj,name,height,label=None,fit_arcs=True):
-
- obj = self._makeCompound(obj,name,label=label,
- fuse=True,fit_arcs=fit_arcs)
+ obj = self._makeCompound(obj, name, label=label, fuse=True, fit_arcs=fit_arcs)
if not self.add_feature:
- return obj.extrude(Vector(0,0,height))
+ return obj.extrude(Vector(0, 0, height))
- nobj = self._makeObject('Part::Extrusion',
- '{}_solid'.format(name),label)
+ nobj = self._makeObject("Part::Extrusion", f"{name}_solid", label)
nobj.Base = obj
- nobj.Dir = Vector(0,0,height)
+ nobj.Dir = Vector(0, 0, height)
obj.ViewObject.Visibility = False
recomputeObj(nobj)
return nobj
-
- def _makeFuse(self,objs,name,label=None,force=False):
+ def _makeFuse(self, objs, name, label=None, force=False):
obj = unpack(objs)
- if not isinstance(obj,(list,tuple)):
+ if not isinstance(obj, (list, tuple)):
if not force:
return obj
obj = [obj]
- name = '{}_fuse'.format(name)
+ name = f"{name}_fuse"
if self.add_feature:
- self._log('making fuse {}...',name)
- obj = self._makeObject('Part::MultiFuse',name,label,'Shapes',obj)
- self._log('fuse done')
+ self._log("making fuse {}...", name)
+ obj = self._makeObject("Part::MultiFuse", name, label, "Shapes", obj)
+ self._log("fuse done")
return obj
solids = []
for o in obj:
- solids += o.Solids;
+ solids += o.Solids
if solids:
- self._log('making fuse {}...',name)
+ self._log("making fuse {}...", name)
obj = solids[0].multiFuse(solids[1:])
- self._log('fuse done')
+ self._log("fuse done")
return obj
+ return None
-
- def _makeCut(self,base,tool,name,label=None):
- base = self._makeFuse(base,name,label=label)
- tool = self._makeFuse(tool,'drill',label=label)
- name = '{}_drilled'.format(name)
- self._log('making cut {}...',name)
+ def _makeCut(self, base, tool, name, label=None):
+ base = self._makeFuse(base, name, label=label)
+ tool = self._makeFuse(tool, "drill", label=label)
+ name = f"{name}_drilled"
+ self._log("making cut {}...", name)
if self.add_feature:
- cut = self._makeObject('Part::Cut',name,label=label)
+ cut = self._makeObject("Part::Cut", name, label=label)
cut.Base = base
cut.Tool = tool
base.ViewObject.Visibility = False
@@ -1268,20 +1281,19 @@ def _makeCut(self,base,tool,name,label=None):
cut.ViewObject.ShapeColor = base.ViewObject.ShapeColor
else:
cut = base.cut(tool)
- #cut = base.cut(tool,0.00006) # maui fuzzy cut ,0.01) # maui
- #print('cutting test?')
- self._log('cut done')
+ # cut = base.cut(tool,0.00006) # maui fuzzy cut ,0.01) # maui
+ # print('cutting test?')
+ self._log("cut done")
return cut
-
- def _place(self,obj,pos,angle=None):
- if not obj.isDerivedFrom('App::DocumentObject'):
+ def _place(self, obj, pos, angle=None):
+ if not obj.isDerivedFrom("App::DocumentObject"):
if angle:
- obj.rotate(Vector(),Vector(0,0,1),angle)
+ obj.rotate(Vector(), Vector(0, 0, 1), angle)
obj.translate(pos)
else:
- r = Rotation(Vector(0,0,1),angle) if angle else Rotation()
- obj.Placement = Placement(pos,r)
+ r = Rotation(Vector(0, 0, 1), angle) if angle else Rotation()
+ obj.Placement = Placement(pos, r)
obj.purgeTouched()
def _makeEdgeCuts(self, sexp, ctx, wires, non_closed, at=None, layers=None):
@@ -1290,7 +1302,7 @@ def _makeEdgeCuts(self, sexp, ctx, wires, non_closed, at=None, layers=None):
layers = [44]
for l in layers:
try:
- _,layer = self.findLayer(l)
+ _, layer = self.findLayer(l)
except Exception:
continue
self._makeShape(sexp, ctx, wires, non_closed, layer, at)
@@ -1303,16 +1315,16 @@ def _makeShape(self, sexp, ctx, wires, non_closed=None, layer=None, at=None):
else:
angle = None
- for tp in 'line','arc','circle','curve','poly','rect':
- name = ctx + '_' + tp
+ for tp in "line", "arc", "circle", "curve", "poly", "rect":
+ name = ctx + "_" + tp
primitives = getattr(sexp, name, None)
if not primitives:
- continue;
+ continue
primitives = SexpList(primitives)
- self._log('making {} {}s',len(primitives), tp)
- try: # maui
- make_shape = globals()['make_gr_{}'.format(tp)]
- if tp == 'poly': # maui
+ self._log("making {} {}s", len(primitives), tp)
+ try: # maui
+ make_shape = globals()[f"make_gr_{tp}"]
+ if tp == "poly": # maui
for l in primitives:
if not layer:
if self.filterNets(l) or self.filterLayer(l):
@@ -1321,15 +1333,15 @@ def _makeShape(self, sexp, ctx, wires, non_closed=None, layer=None, at=None):
continue
shape = make_fp_poly(l)
if angle:
- shape.rotate(Vector(),Vector(0,0,1),angle)
+ shape.rotate(Vector(), Vector(0, 0, 1), angle)
if at:
shape.translate(at)
- #Part.show(shape)
+ # Part.show(shape)
ws = shape.Wires
for w_ in ws:
wires.append(w_)
- #s = Part.Face(shape.Wires[0])
- #Part.show(s)
+ # s = Part.Face(shape.Wires[0])
+ # Part.show(s)
else:
for l in primitives:
if not layer:
@@ -1339,16 +1351,16 @@ def _makeShape(self, sexp, ctx, wires, non_closed=None, layer=None, at=None):
continue
shape = make_shape(l)
if angle:
- shape.rotate(Vector(),Vector(0,0,1),angle)
+ shape.rotate(Vector(), Vector(0, 0, 1), angle)
if at:
shape.translate(at)
- edges += [[getattr(l,'width',1e-7), e] for e in shape.Edges]
- except Exception as e:# maui logging error
+ edges += [[getattr(l, "width", 1e-7), e] for e in shape.Edges]
+ except Exception: # maui logging error
# raise
- # traceback.print_exc() # maui
- error_message = traceback.format_exc() #maui
- self._log('{}',error_message,level='error') # maui
- pass # maui logging error
+ # traceback.print_exc() # maui
+ error_message = traceback.format_exc() # maui
+ self._log("{}", error_message, level="error") # maui
+ # maui logging error
# The line width in edge cuts are important. When milling, the line
# width can represent the diameter of the drill bits to use. The user
# can use lines thick enough for hole cutting. In addition, the
@@ -1359,103 +1371,102 @@ def _makeShape(self, sexp, ctx, wires, non_closed=None, layer=None, at=None):
# shall thicken the wire using Path.Area for hole cutting.
for info in edges:
- w,e = info
+ w, e = info
if w > 1e-7:
e.fixTolerance(w)
- info += [e.firstVertex().Point,e.lastVertex().Point]
+ info += [e.firstVertex().Point, e.lastVertex().Point]
while edges:
- w,e,pstart,pend = edges.pop(-1)
+ w, e, pstart, pend = edges.pop(-1)
wstart = wend = w
- elist = [(w,e)]
+ elist = [(w, e)]
closed = False
i = 0
while i < len(edges):
- w,e,ps,pe = edges[i]
- if pstart.distanceToPoint(ps) <= (wstart+w)/2:
+ w, e, ps, pe = edges[i]
+ if pstart.distanceToPoint(ps) <= (wstart + w) / 2:
e.reverse()
pstart = pe
wstart = w
- elist.insert(0,(w,e))
- elif pstart.distanceToPoint(pe) <= (wstart+w)/2:
+ elist.insert(0, (w, e))
+ elif pstart.distanceToPoint(pe) <= (wstart + w) / 2:
pstart = ps
wstart = w
- elist.insert(0,(w,e))
- elif pend.distanceToPoint(ps) <= (wend+w)/2:
+ elist.insert(0, (w, e))
+ elif pend.distanceToPoint(ps) <= (wend + w) / 2:
e.reverse()
pend = pe
wend = w
- elist.append((w,e))
- elif pend.distanceToPoint(pe) <= (wend+w)/2:
+ elist.append((w, e))
+ elif pend.distanceToPoint(pe) <= (wend + w) / 2:
pend = ps
wend = w
- elist.append((w,e))
+ elist.append((w, e))
else:
i += 1
continue
edges.pop(i)
i = 0
- if pstart.distanceToPoint(pend) <= (wstart+wend)/2:
+ if pstart.distanceToPoint(pend) <= (wstart + wend) / 2:
closed = True
break
wire = None
- try:
- # tol = max([o[0] for o in elist])
- # wire = Part.makeWires([o[1] for o in elist],'',tol,True)
-
+ with contextlib.suppress(Exception):
wire = Part.Wire([o[1] for o in elist])
- # wire.fixWire(None,tol)
- # wire.fix(tol,tol,tol)
- except Exception:
- pass
if closed and (not wire or not wire.isClosed()):
- logger.warning('wire not closed')
+ logger.warning("wire not closed")
closed = False
if wire and closed:
wires.append(wire)
elif non_closed is not None:
- for w,e in elist:
+ for w, e in elist:
if w > 5e-7:
non_closed[w].append(e)
else:
- for w,e in elist:
+ for w, e in elist:
if w > 5e-7:
- wires.append(self._makeWires(e, name=None, offset=w*0.5))
-
- def makeBoard(self,shape_type='solid',thickness=None,fit_arcs=True,
- holes=True, minHoleSize=0,ovalHole=True,prefix=''):
+ wires.append(self._makeWires(e, name=None, offset=w * 0.5))
+
+ def makeBoard(
+ self,
+ shape_type="solid",
+ thickness=None,
+ fit_arcs=True,
+ holes=True,
+ minHoleSize=0,
+ ovalHole=True,
+ prefix="",
+ ):
non_closed = defaultdict(list)
wires = []
- self._pushLog('making board...',prefix=prefix)
- self._makeEdgeCuts(self.pcb, 'gr', wires, non_closed)
+ self._pushLog("making board...", prefix=prefix)
+ self._makeEdgeCuts(self.pcb, "gr", wires, non_closed)
- self._pushLog('checking footprints...',prefix=prefix)
+ self._pushLog("checking footprints...", prefix=prefix)
if self.module:
# try Edge.Cuts first
- self._makeEdgeCuts(self.module, 'fp', wires, non_closed)
+ self._makeEdgeCuts(self.module, "fp", wires, non_closed)
# try F.CrtYd and B.CrtYd
- self._makeEdgeCuts(self.module, 'fp', wires, non_closed, layers=(46, 47))
+ self._makeEdgeCuts(self.module, "fp", wires, non_closed, layers=(46, 47))
else:
for m in self.pcb.module:
- self._makeEdgeCuts(m, 'fp', wires, non_closed, getattr(m, 'at', None))
+ self._makeEdgeCuts(m, "fp", wires, non_closed, getattr(m, "at", None))
self._popLog()
- if not wires and not non_closed:
- if not wires and not non_closed:
- self._popLog('no board edges found')
- return
+ if not wires and not non_closed and not wires and not non_closed:
+ self._popLog("no board edges found")
+ return None
def _addHoles(objs):
- h = self._cutHoles(None,holes,None,
- minSize=minHoleSize,oval=ovalHole)
+ h = self._cutHoles(None, holes, None, minSize=minHoleSize, oval=ovalHole)
if h:
- if isinstance(h,(tuple,list)):
+ if isinstance(h, (tuple, list)):
objs += h
elif holes:
objs.append(h)
@@ -1465,41 +1476,39 @@ def _wire():
objs = []
if wires:
- objs.append(self._makeWires(wires,'board'))
+ objs.append(self._makeWires(wires, "board"))
- for width,edges in non_closed.items():
- objs.append(self._makeWires(edges,'board',label=width,offset=width*0.5))
+ for width, edges in non_closed.items():
+ objs.append(self._makeWires(edges, "board", label=width, offset=width * 0.5))
- return self._makeCompound(_addHoles(objs),'board')
+ return self._makeCompound(_addHoles(objs), "board")
def _face():
if not wires:
- raise RuntimeError('no closed wire')
+ raise RuntimeError("no closed wire")
# Pick the wire with the largest area as outline
- areas = [ Part.Face(w).Area for w in wires ]
+ areas = [Part.Face(w).Area for w in wires]
outer = wires.pop(areas.index(max(areas)))
- objs = [ self._makeWires(outer,'board',label='outline') ]
+ objs = [self._makeWires(outer, "board", label="outline")]
if wires:
- objs.append(self._makeWires(wires,'board',label='inner'))
+ objs.append(self._makeWires(wires, "board", label="inner"))
- for width,elist in non_closed.items():
- wire = self._makeWires(elist,'board',label=width)
+ for width, elist in non_closed.items():
+ wire = self._makeWires(elist, "board", label=width)
# thicken non closed wire for hole cutting
- objs.append(self._makeArea(wire,'board',label=width,
- offset = width*0.5))
+ objs.append(self._makeArea(wire, "board", label=width, offset=width * 0.5))
- return self._makeArea(_addHoles(objs),'board',
- op=1,fill=True,fit_arcs=fit_arcs)
+ return self._makeArea(_addHoles(objs), "board", op=1, fill=True, fit_arcs=fit_arcs)
base = []
+
def _solid():
base.append(_face())
- return self._makeSolid(base[0],'board',thickness,
- fit_arcs = fit_arcs)
+ return self._makeSolid(base[0], "board", thickness, fit_arcs=fit_arcs)
- if shape_type == 'solid' and not thickness and self._dielectric_layers:
+ if shape_type == "solid" and not thickness and self._dielectric_layers:
layers = self._dielectric_layers
else:
if not thickness:
@@ -1510,135 +1519,144 @@ def _solid():
layer_save = self.layer
self.layer = None
try:
- func = locals()['_{}'.format(shape_type)]
+ func = locals()[f"_{shape_type}"]
except KeyError:
- raise ValueError('invalid shape type: {}'.format(shape_type))
+ raise ValueError(f"invalid shape type: {shape_type}")
thickness = layers[0][1]
obj = func()
if self.add_feature:
- if hasattr(obj.ViewObject,'MapFaceColor'):
+ if hasattr(obj.ViewObject, "MapFaceColor"):
obj.ViewObject.MapFaceColor = False
- obj.ViewObject.ShapeColor = self.colors['board']
+ obj.ViewObject.ShapeColor = self.colors["board"]
if len(layers) > 1:
objs = [obj]
for offset, t in layers[1:]:
if abs(t - layers[0][1]) < 1e-7:
if self.add_feature:
- obj = self._makeObject('Part::Feature', 'board_solid')
+ obj = self._makeObject("Part::Feature", "board_solid")
obj.Shape = objs[0].Shape
else:
obj = objs[0].copy()
else:
- obj = self._makeSolid(base[0], 'board', t)
- self._place(obj,Vector(0,0,offset))
+ obj = self._makeSolid(base[0], "board", t)
+ self._place(obj, Vector(0, 0, offset))
if self.add_feature:
- if hasattr(obj.ViewObject,'MapFaceColor'):
+ if hasattr(obj.ViewObject, "MapFaceColor"):
obj.ViewObject.MapFaceColor = False
- obj.ViewObject.ShapeColor = self.colors['board']
+ obj.ViewObject.ShapeColor = self.colors["board"]
objs.append(obj)
- obj = self._makeCompound(objs, 'board')
+ obj = self._makeCompound(objs, "board")
finally:
if layer_save:
self.setLayer(layer_save)
- self._popLog('board done')
- fitView();
+ self._popLog("board done")
+ fitView()
return obj
- def makeHoles(self,shape_type='wire',minSize=0,maxSize=0,
- oval=False,prefix='',offset=0.0,npth=0,skip_via=False,
- board_thickness=None,extra_thickness=0.0):
-
- self._pushLog('making holes...',prefix=prefix)
+ def makeHoles(
+ self,
+ shape_type="wire",
+ minSize=0,
+ maxSize=0,
+ oval=False,
+ prefix="",
+ offset=0.0,
+ npth=0,
+ skip_via=False,
+ board_thickness=None,
+ extra_thickness=0.0,
+ ):
+
+ self._pushLog("making holes...", prefix=prefix)
holes = defaultdict(list)
ovals = defaultdict(list)
- width=0
- def _wire(obj,name,fill=False):
- return self._makeWires(obj,name,fill=fill,label=width)
+ width = 0
+
+ def _wire(obj, name, fill=False):
+ return self._makeWires(obj, name, fill=fill, label=width)
- def _face(obj,name):
- return _wire(obj,name,True)
+ def _face(obj, name):
+ return _wire(obj, name, True)
- def _solid(obj,name):
- return self._makeWires(obj,name,fill=True,label=width,fit_arcs=True)
+ def _solid(obj, name):
+ return self._makeWires(obj, name, fill=True, label=width, fit_arcs=True)
try:
- func = locals()['_{}'.format(shape_type)]
+ func = locals()[f"_{shape_type}"]
except KeyError:
- raise ValueError('invalid shape type: {}'.format(shape_type))
+ raise ValueError(f"invalid shape type: {shape_type}")
oval_count = 0
count = 0
skip_count = 0
if not offset:
- offset = self.hole_size_offset;
+ offset = self.hole_size_offset
for m in self.pcb.module:
- m_at,m_angle = getAt(m)
+ m_at, m_angle = getAt(m)
for p in m.pad:
- #print (str(p))
- if 'drill' not in p:
+ # print (str(p))
+ if "drill" not in p:
continue
if self.filterNets(p):
skip_count += 1
continue
- if p[1]=='np_thru_hole':
- if npth<0:
+ if p[1] == "np_thru_hole":
+ if npth < 0:
skip_count += 1
continue
ofs = abs(offset)
else:
- if npth>0:
+ if npth > 0:
skip_count += 1
continue
ofs = -abs(offset)
- #if 'oval' in str(p.drill):
- #print(str(p.drill))
+ # if 'oval' in str(p.drill):
+ # print(str(p.drill))
# print(p.drill.oval)
- #if hasattr(p.drill, 'oval'):
- #if p.drill.oval: #if 'oval' in str(p.drill): #p.drill.oval:
+ # if hasattr(p.drill, 'oval'):
+ # if p.drill.oval: #if 'oval' in str(p.drill): #p.drill.oval:
if p.drill.oval:
if not oval:
continue
- #print(str(p.drill[1]))
- #if isinstance(p.drill, list):
+ # print(str(p.drill[1]))
+ # if isinstance(p.drill, list):
# print('list')
- #print(str(p.drill[1]))
- #size = Vector(p.drill[1],p.drill[2])
- if len (p.drill) == 2:
- size = Vector(p.drill[0],p.drill[0])
- FreeCAD.Console.PrintWarning('fake oval pad\n')
+ # print(str(p.drill[1]))
+ # size = Vector(p.drill[1],p.drill[2])
+ if len(p.drill) == 2:
+ size = Vector(p.drill[0], p.drill[0])
+ FreeCAD.Console.PrintWarning("fake oval pad\n")
else:
- size = Vector(p.drill[0],p.drill[1])
- w = make_oval(size+Vector(ofs,ofs))
- ovals[min(size.x,size.y)].append(w)
+ size = Vector(p.drill[0], p.drill[1])
+ w = make_oval(size + Vector(ofs, ofs))
+ ovals[min(size.x, size.y)].append(w)
oval_count += 1
- elif 0 in p.drill and \
- p.drill[0]>=minSize and \
- (not maxSize or p.drill[0]<=maxSize):
- w = make_circle(Vector(p.drill[0]+ofs))
+ elif 0 in p.drill and p.drill[0] >= minSize and (not maxSize or p.drill[0] <= maxSize):
+ w = make_circle(Vector(p.drill[0] + ofs))
holes[p.drill[0]].append(w)
count += 1
else:
skip_count += 1
continue
- at,angle = getAt(p)
- angle -= m_angle;
+ at, angle = getAt(p)
+ angle -= m_angle
if not isZero(angle):
- w.rotate(Vector(),Vector(0,0,1),angle)
+ w.rotate(Vector(), Vector(0, 0, 1), angle)
w.translate(at)
if m_angle:
- w.rotate(Vector(),Vector(0,0,1),m_angle)
+ w.rotate(Vector(), Vector(0, 0, 1), m_angle)
w.translate(m_at)
- self._log('pad holes: {}, skipped: {}',count+skip_count,skip_count)
+ self._log("pad holes: {}, skipped: {}", count + skip_count, skip_count)
if oval:
- self._log('oval holes: {}',oval_count)
+ self._log("oval holes: {}", oval_count)
blind_holes = defaultdict(list)
- if npth<=0:
+ if npth <= 0:
via_skip = 0
if skip_via or self.via_bound < 0:
via_skip = len(self.pcb.via)
@@ -1652,39 +1670,37 @@ def _solid(obj,name):
if self.filterNets(v):
via_skip += 1
continue
- if hasattr(v,'drill'): # maui
- if v.drill>=minSize and (not maxSize or v.drill<=maxSize):
-
+ if hasattr(v, "drill"): # maui
+ if v.drill >= minSize and (not maxSize or v.drill <= maxSize):
z_offsets = [layer_offsets[unquote(n)] for n in v.layers]
pos = makeVect(v.at)
pos.z = min(z_offsets)
dist = max(z_offsets) - pos.z
-
- s = v.drill+ofs
+
+ s = v.drill + ofs
if self.via_bound:
s *= self.via_bound
- w = make_rect(Vector(s,s))
+ w = make_rect(Vector(s, s))
else:
w = make_circle(Vector(s))
w.translate(pos)
- if dist < thickness-0.001:
- blind_holes[(pos.z,dist)].append(w)
+ if dist < thickness - 0.001:
+ blind_holes[(pos.z, dist)].append(w)
else:
holes[v.drill].append(w)
- else: # maui
+ else: # maui
via_skip += 1
- else: # maui
+ else: # maui
via_skip += 1
- self._log('drill missing', level='warning') #maui
+ self._log("drill missing", level="warning") # maui
skip_count += via_skip
- self._log('via holes: {}, skipped: {}',len(self.pcb.via),via_skip)
+ self._log("via holes: {}, skipped: {}", len(self.pcb.via), via_skip)
- if blind_holes and shape_type != 'solid':
- self._log('skip blind via holes: {}',len(blind_holes))
+ if blind_holes and shape_type != "solid":
+ self._log("skip blind via holes: {}", len(blind_holes))
blind_holes = None
- self._log('total holes added: {}',
- count+oval_count+len(self.pcb.via)-skip_count)
+ self._log("total holes added: {}", count + oval_count + len(self.pcb.via) - skip_count)
objs = []
if blind_holes or holes or ovals:
@@ -1693,62 +1709,68 @@ def _solid(obj,name):
objs += o
for o in holes.values():
objs += o
- objs = func(objs,"holes")
+ objs = func(objs, "holes")
else:
- for r in ((ovals,'oval'),(holes,'hole')):
+ for r in ((ovals, "oval"), (holes, "hole")):
if not r[0]:
continue
- for (width,rs) in r[0].items():
- objs.append(func(rs,r[1]))
+ for width, rs in r[0].items():
+ objs.append(func(rs, r[1]))
if not npth:
- label=None
- elif npth>0:
- label='npth'
+ label = None
+ elif npth > 0:
+ label = "npth"
else:
- label='th'
+ label = "th"
if not objs:
- self._popLog('no holes')
- return
+ self._popLog("no holes")
+ return None
- if shape_type != 'solid':
- objs = self._makeCompound(objs,'holes',label=label)
+ if shape_type != "solid":
+ objs = self._makeCompound(objs, "holes", label=label)
else:
- if board_thickness:
- thickness = board_thickness
- else:
- thickness = self.board_thickness
+ thickness = board_thickness or self.board_thickness
thickness += extra_thickness
pos = -0.01
- objs = self._makeSolid(objs,'holes',thickness,label=label)
+ objs = self._makeSolid(objs, "holes", thickness, label=label)
if blind_holes:
objs = [objs]
- for (_,d),o in blind_holes.items():
+ for (_, d), o in blind_holes.items():
if npth >= -1:
d += extra_thickness
- objs.append(self._makeSolid(func(o,'blind'),'holes',d,label=label))
- objs = self._makeCompound(objs,'holes',label=label)
- self._place(objs,FreeCAD.Vector(0,0,pos))
+ objs.append(self._makeSolid(func(o, "blind"), "holes", d, label=label))
+ objs = self._makeCompound(objs, "holes", label=label)
+ self._place(objs, FreeCAD.Vector(0, 0, pos))
- if objs: #maui
- self.setColor(objs,'holes')
- self._popLog('holes done')
+ if objs: # maui
+ self.setColor(objs, "holes")
+ self._popLog("holes done")
return objs
-
- def _cutHoles(self,objs,holes,name,label=None,fit_arcs=False,
- minSize=0,maxSize=0,oval=True,npth=0,offset=0.0):
+ def _cutHoles(
+ self,
+ objs,
+ holes,
+ name,
+ label=None,
+ fit_arcs=False,
+ minSize=0,
+ maxSize=0,
+ oval=True,
+ npth=0,
+ offset=0.0,
+ ):
if not holes:
return objs
- if not isinstance(holes,(Part.Feature,Part.Shape)):
+ if not isinstance(holes, (Part.Feature, Part.Shape)):
hit = False
if self.holes_cache is not None:
- key = '{}.{}.{}.{}.{}.{}.{}'.format(
- self.add_feature,minSize,maxSize,oval,npth,offset,self.via_bound)
- doc = getActiveDoc();
- if self.add_feature and self.active_doc_uuid!=doc.Uid:
+ key = f"{self.add_feature}.{minSize}.{maxSize}.{oval}.{npth}.{offset}.{self.via_bound}"
+ doc = getActiveDoc()
+ if self.add_feature and self.active_doc_uuid != doc.Uid:
self.holes_cache.clear()
self.active_doc_uuid = doc.Uid
@@ -1757,8 +1779,7 @@ def _cutHoles(self,objs,holes,name,label=None,fit_arcs=False,
if self.add_feature:
# access the object's Name to make sure it is not
# deleted
- self._log("fetch holes '{}' "
- "from cache".format(holes.Name))
+ self._log(f"fetch holes '{holes.Name}' from cache")
else:
self._log("fetch holes from cache")
hit = True
@@ -1767,11 +1788,18 @@ def _cutHoles(self,objs,holes,name,label=None,fit_arcs=False,
if not hit:
self._pushLog()
- holes = self.makeHoles(shape_type='wire',prefix=None,npth=npth,
- minSize=minSize,maxSize=maxSize,oval=oval,offset=offset)
+ holes = self.makeHoles(
+ shape_type="wire",
+ prefix=None,
+ npth=npth,
+ minSize=minSize,
+ maxSize=maxSize,
+ oval=oval,
+ offset=offset,
+ )
self._popLog()
- if isinstance(self.holes_cache,dict):
+ if isinstance(self.holes_cache, dict):
self.holes_cache[key] = holes
if not holes:
@@ -1780,12 +1808,12 @@ def _cutHoles(self,objs,holes,name,label=None,fit_arcs=False,
if not objs:
return holes
- objs = (self._makeCompound(objs,name,label=label),holes)
- return self._makeArea(objs,name,op=1,label=label,fit_arcs=fit_arcs)
+ objs = (self._makeCompound(objs, name, label=label), holes)
+ return self._makeArea(objs, name, op=1, label=label, fit_arcs=fit_arcs)
def _makeCustomPad(self, params):
wires = []
- # maui
+ # maui
primitive_types = params.primitives
for key in primitive_types:
# If there are multiple primitives of the same type (e.g. gr_arc), the node is parsed
@@ -1793,7 +1821,7 @@ def _makeCustomPad(self, params):
# SexpList if necessary so we can handle both cases the same way.
primitives = SexpList(getattr(primitive_types, key))
for primitive in primitives:
- wire,width = makePrimitve(key, primitive)
+ wire, width = makePrimitve(key, primitive)
if not width:
if isinstance(wire, Part.Edge):
wire = Part.Wire(wire)
@@ -1801,25 +1829,24 @@ def _makeCustomPad(self, params):
elif not wire:
pass
else:
- wire = self._makeWires(wire, name=None, offset=width*0.5)
+ wire = self._makeWires(wire, name=None, offset=width * 0.5)
wires += wire.Wires
# maui end
if not wires:
- return
+ return None
if len(wires) == 1:
return wires[0]
return Part.makeCompound(wires)
- def makePads(self,shape_type='face',thickness=0.05,holes=False,
- fit_arcs=True,prefix=''):
+ def makePads(self, shape_type="face", thickness=0.05, holes=False, fit_arcs=True, prefix=""):
- self._pushLog('making pads...',prefix=prefix)
+ self._pushLog("making pads...", prefix=prefix)
- def _wire(obj,name,label=None,fill=False):
- return self._makeWires(obj,name,fill=fill,label=label, offset=self.pad_inflate)
+ def _wire(obj, name, label=None, fill=False):
+ return self._makeWires(obj, name, fill=fill, label=label, offset=self.pad_inflate)
- def _face(obj,name,label=None):
- objs = _wire(obj,name,label,True)
+ def _face(obj, name, label=None):
+ objs = _wire(obj, name, label, True)
if not cut_wires and not cut_non_closed:
return objs
@@ -1827,133 +1854,130 @@ def _face(obj,name,label=None):
if not isinstance(objs, list):
objs = [objs]
- inner_label = label + '_inner' if label else 'inner'
+ inner_label = label + "_inner" if label else "inner"
if cut_wires:
- objs.append(self._makeWires(cut_wires,name,label=inner_label))
+ objs.append(self._makeWires(cut_wires, name, label=inner_label))
- for width,elist in cut_non_closed.items():
- l = '{}_{}'.format(inner_label, width)
- wire = self._makeWires(elist,name,label=l)
+ for width, elist in cut_non_closed.items():
+ l = f"{inner_label}_{width}"
+ wire = self._makeWires(elist, name, label=l)
# thicken non closed wire for hole cutting
- objs.append(self._makeArea(wire, name, label=l, offset = width*0.5))
+ objs.append(self._makeArea(wire, name, label=l, offset=width * 0.5))
- return self._makeArea(objs, name, op=1,fill=True)
+ return self._makeArea(objs, name, op=1, fill=True)
_solid = _face
try:
- func = locals()['_{}'.format(shape_type)]
+ func = locals()[f"_{shape_type}"]
except KeyError:
- raise ValueError('invalid shape type: {}'.format(shape_type))
+ raise ValueError(f"invalid shape type: {shape_type}")
objs = []
count = 0
skip_count = 0
- for i,m in enumerate(self.pcb.module):
- ref = ''
+ for i, m in enumerate(self.pcb.module):
+ ref = ""
for t in m.fp_text:
- if t[0] == 'reference':
+ if t[0] == "reference":
ref = t[1]
- break;
- m_at,m_angle = getAt(m)
+ break
+ m_at, m_angle = getAt(m)
pads = []
count += len(m.pad)
cut_wires = []
cut_non_closed = defaultdict(list)
- self._pushLog('checking edge cuts')
- self._makeEdgeCuts(m, 'fp', cut_wires, cut_non_closed)
+ self._pushLog("checking edge cuts")
+ self._makeEdgeCuts(m, "fp", cut_wires, cut_non_closed)
self._popLog()
- for j,p in enumerate(m.pad):
+ for j, p in enumerate(m.pad):
if self.filterNets(p) or self.filterLayer(p):
- skip_count+=1
+ skip_count += 1
continue
shape = p[2]
- wp = ''
- if shape == 'custom':
+ wp = ""
+ if shape == "custom":
w = self._makeCustomPad(p)
- #Part.show(w)
+ # Part.show(w)
# maui start
# print(p.size)
# print(p.options.anchor) #maui
- make_shape = globals()['make_{}'.format(p.options.anchor)]
+ make_shape = globals()[f"make_{p.options.anchor}"]
# print(make_shape)
- wp = make_shape(Vector(*p.size),p)
- if shape_type == 'wire':
+ wp = make_shape(Vector(*p.size), p)
+ if shape_type == "wire":
# keeping visualization of internal reference pad ONLY for footprint loading
if w is not None:
- w = Part.makeCompound([w,wp])
- wp = ''
+ w = Part.makeCompound([w, wp])
+ wp = ""
else:
- w=wp
+ w = wp
# Part.show(wp)
# maui end
else:
try:
- make_shape = globals()['make_{}'.format(shape)]
+ make_shape = globals()[f"make_{shape}"]
except KeyError:
- raise NotImplementedError(
- 'pad shape {} not implemented\n'.format(shape))
- w = make_shape(Vector(*p.size),p)
+ raise NotImplementedError(f"pad shape {shape} not implemented\n")
+ w = make_shape(Vector(*p.size), p)
if not w:
continue
# kicad put pad shape offset inside drill element? Why?
- if 'drill' in p and 'offset' in p.drill:
+ if "drill" in p and "offset" in p.drill:
w.translate(makeVect(p.drill.offset))
- if wp != '': # maui
+ if wp != "": # maui
wp.translate(makeVect(p.drill.offset))
-
- at,angle = getAt(p)
- angle -= m_angle;
+
+ at, angle = getAt(p)
+ angle -= m_angle
if not isZero(angle):
- w.rotate(Vector(),Vector(0,0,1),angle)
- if wp != '': # maui
- wp.rotate(Vector(),Vector(0,0,1),angle)
+ w.rotate(Vector(), Vector(0, 0, 1), angle)
+ if wp != "": # maui
+ wp.rotate(Vector(), Vector(0, 0, 1), angle)
w.translate(at)
- if wp != '': # maui
+ if wp != "": # maui
wp.translate(at)
if not self.merge_pads:
- pads.append(func(w,'pad',
- '{}#{}#{}#{}#{}'.format(i,j,p[0],ref,self.netName(p))))
- if wp != '': # maui
- pads.append(func(wp,'pad',
- '{}#{}#{}#{}#{}'.format(i,j,p[0],ref,self.netName(p))))
+ pads.append(func(w, "pad", f"{i}#{j}#{p[0]}#{ref}#{self.netName(p)}"))
+ if wp != "": # maui
+ pads.append(func(wp, "pad", f"{i}#{j}#{p[0]}#{ref}#{self.netName(p)}"))
else:
pads.append(w)
- self._makeShape(m, 'fp', pads)
+ self._makeShape(m, "fp", pads)
if not pads:
continue
if not self.merge_pads:
# maui start
- #print(pads)
- opads=[]
+ # print(pads)
+ opads = []
for p in pads:
- #print(p.TypeId) # wire -> 'Part::TopoShape'
- if ' 'Part::TopoShape'
+ if " max(layers)\
- or self.filterNets(v):
+ if self.layer_type < min(layers) or self.layer_type > max(layers) or self.filterNets(v):
via_skip += 1
continue
if self.via_bound:
- w = make_rect(Vector(v.size*self.via_bound,v.size*self.via_bound))
+ w = make_rect(Vector(v.size * self.via_bound, v.size * self.via_bound))
else:
w = make_circle(Vector(v.size))
w.translate(makeVect(v.at))
if not self.merge_vias:
- vias.append(func(w,'via','{}#{}'.format(i,v.size)))
+ vias.append(func(w, "via", f"{i}#{v.size}"))
else:
vias.append(w)
if vias:
if self.merge_vias:
- objs.append(func(vias,'vias'))
+ objs.append(func(vias, "vias"))
else:
- objs.append(self._makeCompound(vias,'vias'))
+ objs.append(self._makeCompound(vias, "vias"))
- self._log('footprints: {}',len(self.pcb.module))
- self._log('pads: {}, skipped: {}',count,skip_count)
- self._log('vias: {}, skipped: {}',len(self.pcb.via),via_skip)
- self._log('total pads added: {}',
- count-skip_count+len(self.pcb.via)-via_skip)
+ self._log("footprints: {}", len(self.pcb.module))
+ self._log("pads: {}, skipped: {}", count, skip_count)
+ self._log("vias: {}, skipped: {}", len(self.pcb.via), via_skip)
+ self._log("total pads added: {}", count - skip_count + len(self.pcb.via) - via_skip)
if objs:
- objs = self._cutHoles(objs,holes,'pads',fit_arcs=fit_arcs)
- if shape_type=='solid':
- objs = self._makeSolid(objs,'pads', thickness,
- fit_arcs = fit_arcs)
+ objs = self._cutHoles(objs, holes, "pads", fit_arcs=fit_arcs)
+ if shape_type == "solid":
+ objs = self._makeSolid(objs, "pads", thickness, fit_arcs=fit_arcs)
else:
- objs = self._makeCompound(objs,'pads',
- fuse=True,fit_arcs=fit_arcs)
- self.setColor(objs,'pad')
+ objs = self._makeCompound(objs, "pads", fuse=True, fit_arcs=fit_arcs)
+ self.setColor(objs, "pad")
- self._popLog('pads done')
- fitView();
+ self._popLog("pads done")
+ fitView()
return objs
-# maui
- def makeNetTies(self,shape_type='face',thickness=0.05,holes=False,
- fit_arcs=True,prefix=''):
+ # maui
+ def makeNetTies(self, shape_type="face", thickness=0.05, holes=False, fit_arcs=True, prefix=""):
- self._pushLog('making net ties...',prefix=prefix)
+ self._pushLog("making net ties...", prefix=prefix)
- def _wire(obj,name,label=None,fill=False):
- return self._makeWires(obj,name,fill=fill,label=label, offset=self.pad_inflate)
+ def _wire(obj, name, label=None, fill=False):
+ return self._makeWires(obj, name, fill=fill, label=label, offset=self.pad_inflate)
- def _face(obj,name,label=None):
- objs = _wire(obj,name,label,True)
+ def _face(obj, name, label=None):
+ objs = _wire(obj, name, label, True)
if not cut_wires and not cut_non_closed:
return objs
@@ -2025,108 +2043,102 @@ def _face(obj,name,label=None):
if not isinstance(objs, list):
objs = [objs]
- inner_label = label + '_inner' if label else 'inner'
+ inner_label = label + "_inner" if label else "inner"
if cut_wires:
- objs.append(self._makeWires(cut_wires,name,label=inner_label))
+ objs.append(self._makeWires(cut_wires, name, label=inner_label))
- for width,elist in cut_non_closed.items():
- l = '{}_{}'.format(inner_label, width)
- wire = self._makeWires(elist,name,label=l)
+ for width, elist in cut_non_closed.items():
+ l = f"{inner_label}_{width}"
+ wire = self._makeWires(elist, name, label=l)
# thicken non closed wire for hole cutting
- objs.append(self._makeArea(wire, name, label=l, offset = width*0.5))
+ objs.append(self._makeArea(wire, name, label=l, offset=width * 0.5))
- return self._makeArea(objs, name, op=1,fill=True)
+ return self._makeArea(objs, name, op=1, fill=True)
_solid = _face
try:
- func = locals()['_{}'.format(shape_type)]
+ func = locals()[f"_{shape_type}"]
except KeyError:
- raise ValueError('invalid shape type: {}'.format(shape_type))
+ raise ValueError(f"invalid shape type: {shape_type}")
objs = []
- ws=[]
- add_rot=0
+ ws = []
+ add_rot = 0
count = 0
skip_count = 0
- for i,m in enumerate(self.pcb.module):
- ref = ''
+ for i, m in enumerate(self.pcb.module):
+ ref = ""
for t in m.fp_text:
- if t[0] == 'reference':
+ if t[0] == "reference":
ref = t[1]
- break;
- m_at,m_angle = getAt(m)
+ break
+ m_at, m_angle = getAt(m)
nt = []
count += len(m.fp_poly)
cut_wires = []
cut_non_closed = defaultdict(list)
- for j,pl in enumerate(m.fp_poly):
+ for j, pl in enumerate(m.fp_poly):
if unquote(pl.layer) == self.layer:
- shape='fp_poly'
+ shape = "fp_poly"
nt = make_fp_poly(pl)
if not nt:
continue
+ ws.append(nt)
+ add_rot = 0
+ if hasattr(m, "model"):
+ # print(m.model[0].rotate.xyz[2])
+ with contextlib.suppress(BaseException):
+ add_rot = m.model[0].rotate.xyz[2]
+
+ if len(ws) > 0:
+ ws = _face(ws, "net-ties")
+ if shape_type == "solid":
+ objs = self._makeSolid(ws, "net-ties", thickness, fit_arcs=fit_arcs)
else:
- ws.append(nt)
- add_rot=0
- if hasattr(m, 'model'):
- #print(m.model[0].rotate.xyz[2])
- try:
- add_rot=m.model[0].rotate.xyz[2]
- except:
- pass
+ objs = self._makeCompound(ws, "net-ties", fuse=True, fit_arcs=fit_arcs)
+ self.setColor(objs, "NetTie")
- if len (ws)>0:
- ws = _face(ws,'net-ties')
- if shape_type=='solid':
- objs = self._makeSolid(ws,'net-ties', thickness,
- fit_arcs = fit_arcs)
- else:
- objs = self._makeCompound(ws,'net-ties',
- fuse=True,fit_arcs=fit_arcs)
- self.setColor(objs,'NetTie')
-
- self._popLog('Net Tie poly done')
- fitView();
- return objs # obj //additional rotation in deg
-
+ self._popLog("Net Tie poly done")
+ fitView()
+ return objs # obj //additional rotation in deg
- def makeSketches(self, fit_arcs=True,prefix=''):
+ def makeSketches(self, fit_arcs=True, prefix=""):
- self._pushLog('making sketches...',prefix=prefix)
+ self._pushLog("making sketches...", prefix=prefix)
- #def _wire(obj,name,label=None,fill=False):
+ # def _wire(obj,name,label=None,fill=False):
# return self._makeWires(obj,name,fill=fill,label=label, offset=self.pad_inflate)
width = 0
- def _line(edges,label,offset=0,fill=False):
+
+ def _line(edges, label, offset=0, fill=False):
wires = findWires(edges)
- return self._makeWires(wires,label, offset=offset,
- fill=fill, label=label, fit_arcs=fit_arcs)
+ return self._makeWires(wires, label, offset=offset, fill=fill, label=label, fit_arcs=fit_arcs)
- def _wire(edges,label,fill=False):
- return _line(edges,label,width*0.5,fill) #*0.5,fill)
+ def _wire(edges, label, fill=False):
+ return _line(edges, label, width * 0.5, fill) # *0.5,fill)
- def _face(edges,label):
- return _wire(edges,label,True)
+ def _face(edges, label):
+ return _wire(edges, label, True)
+
+ _solid = _face
- _solid = _face
-
obj = []
tbd = []
count = 0
skip_count = 0
- for i,m in enumerate(self.pcb.module):
- ref = ''
+ for i, m in enumerate(self.pcb.module):
+ ref = ""
for t in m.fp_text:
- if t[0] == 'reference':
+ if t[0] == "reference":
ref = t[1]
- break;
- m_at,m_angle = getAt(m)
+ break
+ m_at, m_angle = getAt(m)
pads = []
count += len(m.pad)
@@ -2136,153 +2148,159 @@ def _face(edges,label):
# self._pushLog('checking edge cuts')
# self._makeEdgeCuts(m, 'fp', cut_wires, cut_non_closed)
# self._popLog()
- ws=[]
- wst=[]
- objs=[]
- tl=None
+ ws = []
+ wst = []
+ objs = []
+ tl = None
_solid = _face
-
+
# test creating pads from gr_poly
# print (' test creating pads from gr_poly')
- for j,p in enumerate(m.pad):
- #print(unquote(p.layers))
+ for j, p in enumerate(m.pad):
+ # print(unquote(p.layers))
poly = []
- #print(self.layer,unquote(p.layers))
+ # print(self.layer,unquote(p.layers))
if self.layer in str(unquote(p.layers)):
shape = p[2]
w = 0
- if shape == 'custom':
+ if shape == "custom":
w = self._makeCustomPad(p)
if not w:
- continue
+ continue
# Part.show(w)
- at,angle = getAt(p)
- angle -= m_angle;
+ at, angle = getAt(p)
+ angle -= m_angle
if not isZero(angle):
- w.rotate(Vector(),Vector(0,0,1),angle)
+ w.rotate(Vector(), Vector(0, 0, 1), angle)
w.translate(at)
-
+
poly.append(w)
- self._makeShape(m, 'fp', poly)
-
+ self._makeShape(m, "fp", poly)
+
if not poly:
continue
- shape_type='solid'
+ shape_type = "solid"
try:
- func = locals()['_{}'.format(shape_type)]
+ func = locals()[f"_{shape_type}"]
except KeyError:
- raise ValueError('invalid shape type: {}'.format(shape_type))
-
- #print(poly)
+ raise ValueError(f"invalid shape type: {shape_type}")
+
+ # print(poly)
for wr in poly:
- objp = func(wr.Edges,'pads') #,'{}#{}'.format(i,ref))
- self._place(objp,m_at,m_angle)
+ objp = func(wr.Edges, "pads") # ,'{}#{}'.format(i,ref))
+ self._place(objp, m_at, m_angle)
objs.append(objp)
- if len(objs)>0:
+ if len(objs) > 0:
for o in objs:
- self.setPadColor(o,unquote(self.layer_name))
- #print (objs)
+ self.setPadColor(o, unquote(self.layer_name))
+ # print (objs)
# end test creating pads from gr_poly
-
- for j,l in enumerate(m.fp_line):
+
+ for j, l in enumerate(m.fp_line):
if unquote(l.layer) == self.layer:
- #print(j,l)
- try: #avoiding null lenght lines
- ws.append((Part.Wire(make_gr_line(l))))
- #wst.append(Part.Face(makeThickLine(makeVect(l.start),makeVect(l.end),l.width)))
- #print ('l.width',hasattr(l,'width'))
- #print ('l.stroke',hasattr(l,'stroke'))
- if hasattr(l,'stroke'):
- #print(l.stroke.width)
- wst.append(makeThickLine(makeVect(l.start),makeVect(l.end),l.stroke.width/2.0))
+ # print(j,l)
+ try: # avoiding null lenght lines
+ ws.append(Part.Wire(make_gr_line(l)))
+ # wst.append(Part.Face(makeThickLine(makeVect(l.start),makeVect(l.end),l.width)))
+ # print ('l.width',hasattr(l,'width'))
+ # print ('l.stroke',hasattr(l,'stroke'))
+ if hasattr(l, "stroke"):
+ # print(l.stroke.width)
+ wst.append(makeThickLine(makeVect(l.start), makeVect(l.end), l.stroke.width / 2.0))
else:
- wst.append(makeThickLine(makeVect(l.start),makeVect(l.end),l.width/2.0))
- #self._makeShape(m, 'fp', ws)
+ wst.append(makeThickLine(makeVect(l.start), makeVect(l.end), l.width / 2.0))
+ # self._makeShape(m, 'fp', ws)
except:
pass
- for j,l in enumerate(m.fp_rect):
+ for j, l in enumerate(m.fp_rect):
if unquote(l.layer) == self.layer:
- #print(j,l)
- try: #avoiding null lenght lines
- rc=Part.Wire(make_gr_rect(l))
+ # print(j,l)
+ try: # avoiding null lenght lines
+ rc = Part.Wire(make_gr_rect(l))
ws.append(rc)
- if hasattr(l,'stroke'):
- #print(l.stroke.width)
+ if hasattr(l, "stroke"):
+ # print(l.stroke.width)
width = l.stroke.width
else:
width = l.width
for e in rc.Edges:
- wst.append(makeThickLine(makeVect([e.Vertexes[0].X,-e.Vertexes[0].Y]),makeVect([e.Vertexes[1].X,-e.Vertexes[1].Y]),width/2.0))
+ wst.append(
+ makeThickLine(
+ makeVect([e.Vertexes[0].X, -e.Vertexes[0].Y]),
+ makeVect([e.Vertexes[1].X, -e.Vertexes[1].Y]),
+ width / 2.0,
+ ),
+ )
except:
pass
- for j,a in enumerate(m.fp_arc):
+ for j, a in enumerate(m.fp_arc):
if unquote(a.layer) == self.layer:
- #print(j,l.start)
+ # print(j,l.start)
ac = Part.Wire(make_gr_arc(a))
- ws.append((Part.Wire(make_gr_arc(a))))
- if hasattr(a,'stroke'):
- width = a.stroke.width
- else:
- width = a.width
- aco=_wire(ac.Edges,self.layer)
+ ws.append(Part.Wire(make_gr_arc(a)))
+ width = a.stroke.width if hasattr(a, "stroke") else a.width
+ aco = _wire(ac.Edges, self.layer)
wst.append(aco.Shape)
tbd.append(aco)
- #doc=FreeCAD.ActiveDocument
- #doc.recompute()
- #try:
+ # doc=FreeCAD.ActiveDocument
+ # doc.recompute()
+ # try:
# doc.removeObject(doc.getObject(aco.Name).Outlist[0].Name)
- #except:
+ # except:
# pass
- #doc.removeObject(aco.Name)
- #if hasattr(a, 'angle'):
+ # doc.removeObject(aco.Name)
+ # if hasattr(a, 'angle'):
# wst.append(makeArc(makeVect(a.start),makeVect(a.end),a.angle))
- #else:
+ # else:
# wst.append(Part.ArcOfCircle(makeVect(a.start),makeVect(a.mid),makeVect(a.end)).toShape())
- for j,c in enumerate(m.fp_circle):
+ for j, c in enumerate(m.fp_circle):
if unquote(c.layer) == self.layer:
- #print(j,l.start)
- ws.append((Part.Wire(make_gr_circle(c))))
+ # print(j,l.start)
+ ws.append(Part.Wire(make_gr_circle(c)))
##ws.append((Part.Wire(make_gr_circle(c).Edges)))
- if hasattr(c,'stroke'):
- cc=make_gr_circle_outl(c,c.stroke.width)
+ if hasattr(c, "stroke"):
+ cc = make_gr_circle_outl(c, c.stroke.width)
else:
- cc=make_gr_circle_outl(c,c.width)
- if isinstance(cc,list):
+ cc = make_gr_circle_outl(c, c.width)
+ if isinstance(cc, list):
wst.append(Part.Wire(cc[0]))
wst.append(Part.Wire(cc[1]))
else:
wst.append(Part.Wire(cc))
- #wst.append((Part.Wire(make_gr_circle(c,c.width)
-
+ # wst.append((Part.Wire(make_gr_circle(c,c.width)
+
# Part.show(Part.Wire(make_gr_circle(c,c.width).Edges))
# wst.append((Part.Wire(make_gr_circle(c,c.width).Edges)))
if 0:
- ce=make_gr_circle_outl(c,-c.width)
+ ce = make_gr_circle_outl(c, -c.width)
if ce is not None:
wst.append(Part.Wire(ce))
- ci=Part.Wire(make_gr_circle_outl(c,+c.width))
+ ci = Part.Wire(make_gr_circle_outl(c, +c.width))
wst.append(ci)
# try:
# wst.append((Part.Wire(make_gr_circle(c,c.width))))
# except:
# wst.append((make_gr_circle(c,c.width)))
- #manca_thick_circle
- for j,pl in enumerate(m.fp_poly):
+ # manca_thick_circle
+ for j, pl in enumerate(m.fp_poly):
if unquote(pl.layer) == self.layer:
- pln=Part.Wire(make_gr_poly(pl))
- ws.append((pln))
- if hasattr(pl,'stroke'):
- width = pl.stroke.width
- else:
- width = pl.width
+ pln = Part.Wire(make_gr_poly(pl))
+ ws.append(pln)
+ width = pl.stroke.width if hasattr(pl, "stroke") else pl.width
for e in pln.Edges:
- #aco=_wire(e,self.layer)
- wst.append(makeThickLine(makeVect([e.Vertexes[0].X,-e.Vertexes[0].Y]),makeVect([e.Vertexes[1].X,-e.Vertexes[1].Y]),width/2.0))
- #plno=_wire(pln.Edges,self.layer)
+ # aco=_wire(e,self.layer)
+ wst.append(
+ makeThickLine(
+ makeVect([e.Vertexes[0].X, -e.Vertexes[0].Y]),
+ makeVect([e.Vertexes[1].X, -e.Vertexes[1].Y]),
+ width / 2.0,
+ ),
+ )
+ # plno=_wire(pln.Edges,self.layer)
##wst.append(pln)
- #wst.append(plno.Shape)
-
- add_rot=0
+ # wst.append(plno.Shape)
+
+ add_rot = 0
## if hasattr(m, 'model'):
## #print(m.model[0].rotate.xyz[2])
## try:
@@ -2290,193 +2308,181 @@ def _face(edges,label):
## except:
## pass
- if len (wst)>0:
+ if len(wst) > 0:
Part.show(Part.makeCompound(wst))
tl = FreeCAD.ActiveDocument.ActiveObject
- tl.Label = self.layer+'_outline_'
- self._place(tl,m_at,m_angle+add_rot)
+ tl.Label = self.layer + "_outline_"
+ self._place(tl, m_at, m_angle + add_rot)
# del(wst)
-
- #Draft.make_sketch(ws, autoconstraints=False)
- #sp=FreeCAD.ActiveDocument.ActiveObject
- #sk = Draft.make_sketch(ws, autoconstraints=False)
- #sp.ViewObject.Visibility=False
+
+ # Draft.make_sketch(ws, autoconstraints=False)
+ # sp=FreeCAD.ActiveDocument.ActiveObject
+ # sk = Draft.make_sketch(ws, autoconstraints=False)
+ # sp.ViewObject.Visibility=False
if not ws:
continue
obj = self._makeSketch(ws, self.layer_name)
- self._place(obj,m_at,m_angle+add_rot)
- obj.Label= self.layer+'_'
- #objs.append(obj)
+ self._place(obj, m_at, m_angle + add_rot)
+ obj.Label = self.layer + "_"
+ # objs.append(obj)
if obj:
- self.setSketchColor(obj,unquote(self.layer_name))
+ self.setSketchColor(obj, unquote(self.layer_name))
- self._popLog('sketch done')
- fitView();
- return obj,tl,tbd #,add_rot # obj, thicklines, to be deleted, additional rotation in deg
+ self._popLog("sketch done")
+ fitView()
+ return obj, tl, tbd # ,add_rot # obj, thicklines, to be deleted, additional rotation in deg
- def setSketchColor(self,obj,otype):
+ def setSketchColor(self, obj, otype):
if not self.add_feature:
return
try:
color = self.colors[otype][self.layer_type]
except KeyError:
color = self.colors[otype][0]
- #print (color)
- #if
+ # print (color)
+ # if
obj.ViewObject.LineColor = color
- def setPadColor(self,obj,otype):
+ def setPadColor(self, obj, otype):
if not self.add_feature:
return
try:
color = self.colors[otype][self.layer_type]
except KeyError:
color = self.colors[otype][0]
- #print (color)
- #if
+ # print (color)
+ # if
obj.ViewObject.ShapeColor = color
-# maui
- def setColor(self,obj,otype):
+ # maui
+
+ def setColor(self, obj, otype):
if not self.add_feature:
return
try:
color = self.colors[otype][self.layer_type]
except KeyError:
color = self.colors[otype][0]
- if hasattr(obj.ViewObject,'MapFaceColor'):
+ if hasattr(obj.ViewObject, "MapFaceColor"):
obj.ViewObject.MapFaceColor = False
obj.ViewObject.ShapeColor = color
+ def makeTracks(self, shape_type="face", fit_arcs=True, thickness=0.05, holes=False, prefix=""):
- def makeTracks(self,shape_type='face',fit_arcs=True,
- thickness=0.05,holes=False,prefix=''):
-
- self._pushLog('making tracks...',prefix=prefix)
+ self._pushLog("making tracks...", prefix=prefix)
width = 0
- def _line(edges,label,offset=0,fill=False):
+
+ def _line(edges, label, offset=0, fill=False):
wires = findWires(edges)
- return self._makeWires(wires,'track', offset=offset,
- fill=fill, label=label, fit_arcs=fit_arcs)
+ return self._makeWires(wires, "track", offset=offset, fill=fill, label=label, fit_arcs=fit_arcs)
- def _wire(edges,label,fill=False):
- return _line(edges,label,width*0.5,fill)
+ def _wire(edges, label, fill=False):
+ return _line(edges, label, width * 0.5, fill)
- def _face(edges,label):
- return _wire(edges,label,True)
+ def _face(edges, label):
+ return _wire(edges, label, True)
_solid = _face
try:
- func = locals()['_{}'.format(shape_type)]
+ func = locals()[f"_{shape_type}"]
except KeyError:
- raise ValueError('invalid shape type: {}'.format(shape_type))
+ raise ValueError(f"invalid shape type: {shape_type}")
tracks = defaultdict(lambda: defaultdict(list))
count = 0
- for tp,ss in (('segment',self.pcb.segment), ('arc',getattr(self.pcb, 'arc', []))):
+ for tp, ss in (("segment", self.pcb.segment), ("arc", getattr(self.pcb, "arc", []))):
for s in ss:
if self.filterNets(s):
continue
if unquote(s.layer) == self.layer:
if self.merge_tracks:
- tracks[''][s.width].append((tp,s))
+ tracks[""][s.width].append((tp, s))
else:
- tracks[self.netName(s)][s.width].append((tp,s))
+ tracks[self.netName(s)][s.width].append((tp, s))
count += 1
objs = []
i = 0
- for (name,sss) in tracks.items():
- for (width,ss) in sss.items():
- self._log('making {} tracks {} of width {:.2f}, ({}/{})',
- len(ss),name,width,i,count)
- i+=len(ss)
+ for name, sss in tracks.items():
+ for width, ss in sss.items():
+ self._log("making {} tracks {} of width {:.2f}, ({}/{})", len(ss), name, width, i, count)
+ i += len(ss)
edges = []
- for tp,s in ss:
- if tp == 'segment':
+ for tp, s in ss:
+ if tp == "segment":
if s.start != s.end:
- edges.append(Part.makeLine(
- makeVect(s.start),makeVect(s.end)))
+ edges.append(Part.makeLine(makeVect(s.start), makeVect(s.end)))
else:
- self._log('Line (Track) through identical points {}',
- s.start, level="warning")
- elif tp == 'arc':
+ self._log("Line (Track) through identical points {}", s.start, level="warning")
+ elif tp == "arc":
if s.start == s.mid:
- self._log('Arc (Track) with invalid point {}', s, level="warning")
+ self._log("Arc (Track) with invalid point {}", s, level="warning")
elif s.start != s.end:
- edges.append(Part.ArcOfCircle(
- makeVect(s.end), makeVect(s.mid), makeVect(s.start)).toShape())
+ edges.append(
+ Part.ArcOfCircle(makeVect(s.end), makeVect(s.mid), makeVect(s.start)).toShape(),
+ )
else:
start = makeVect(s.start)
middle = makeVect(s.mid)
r = start.distanceToPoint(middle)
- edges.append(Part.makeCircle(r, (middle-start)/2))
+ edges.append(Part.makeCircle(r, (middle - start) / 2))
else:
- self._log('Unknown track type: {}', tp, level='warning')
- if self.merge_tracks:
- label = '{}'.format(width)
- else:
- label = '{}#{}'.format(width,name)
- objs.append(func(edges,label=label))
+ self._log("Unknown track type: {}", tp, level="warning")
+ label = f"{width}" if self.merge_tracks else f"{width}#{name}"
+ objs.append(func(edges, label=label))
if objs:
- objs = self._cutHoles(objs,holes,'tracks',fit_arcs=fit_arcs)
+ objs = self._cutHoles(objs, holes, "tracks", fit_arcs=fit_arcs)
- if shape_type == 'solid':
- objs = self._makeSolid(objs,'tracks',thickness,
- fit_arcs=fit_arcs)
+ if shape_type == "solid":
+ objs = self._makeSolid(objs, "tracks", thickness, fit_arcs=fit_arcs)
else:
- objs = self._makeCompound(objs,'tracks',fuse=True,
- fit_arcs=fit_arcs)
+ objs = self._makeCompound(objs, "tracks", fuse=True, fit_arcs=fit_arcs)
- self.setColor(objs,'track')
+ self.setColor(objs, "track")
- self._popLog('tracks done')
- fitView();
+ self._popLog("tracks done")
+ fitView()
return objs
- def _makePolygons(self, fields, name, poly_holes,
- shape_type='face', thickness=0.05, prefix=''):
+ def _makePolygons(self, fields, name, poly_holes, shape_type="face", thickness=0.05, prefix=""):
if not fields:
return []
count = len(fields)
- self._pushLog(f'making {count} polygons...',prefix=prefix)
+ self._pushLog(f"making {count} polygons...", prefix=prefix)
- def _wire(obj,fill=False):
+ def _wire(obj, fill=False):
- offset = self.zone_inflate + thickness*0.5
+ offset = self.zone_inflate + thickness * 0.5
- if not poly_holes \
- or (self.add_feature and self.make_sketch and self.zone_merge_holes):
- obj = [obj]+poly_holes
+ if not poly_holes or (self.add_feature and self.make_sketch and self.zone_merge_holes):
+ obj = [obj, *poly_holes]
elif poly_holes:
- obj = (self._makeWires(obj,f'{name}_outline'),
- self._makeWires(poly_holes,f'{name}_hole'))
- return self._makeArea(obj,name,offset=offset, op=1, fill=fill)
-
- return self._makeWires(obj,name,fill=fill, offset=offset)
+ obj = (self._makeWires(obj, f"{name}_outline"), self._makeWires(poly_holes, f"{name}_hole"))
+ return self._makeArea(obj, name, offset=offset, op=1, fill=fill)
+ return self._makeWires(obj, name, fill=fill, offset=offset)
def _face(obj):
- return _wire(obj,True)
+ return _wire(obj, True)
_solid = _face
try:
- func = locals()['_{}'.format(shape_type)]
+ func = locals()[f"_{shape_type}"]
except KeyError:
- raise ValueError('invalid shape type: {}'.format(shape_type))
+ raise ValueError(f"invalid shape type: {shape_type}")
objs = []
- for idx,p in enumerate(fields):
- if (hasattr(p, 'layer') or hasattr(p, 'layers')) and self.filterLayer(p):
+ for idx, p in enumerate(fields):
+ if (hasattr(p, "layer") or hasattr(p, "layers")) and self.filterLayer(p):
continue
poly_holes = []
table = {}
@@ -2487,8 +2493,8 @@ def _face(obj):
# `table` uses a pair of vertex as the key to store the index of
# an edge.
- for i in range(len(pts)-1):
- table[str((pts[i],pts[i+1]))] = i
+ for i in range(len(pts) - 1):
+ table[str((pts[i], pts[i + 1]))] = i
# This is how kicad represents holes in zone polygon
# ---------------------------
@@ -2505,68 +2511,63 @@ def _face(obj):
# cancel out those '=' double edges, which will surely cause
# problem if left alone. The algorithm assumes we start with a
# point of the outer polygon.
- def build(start,end):
+ def build(start, end):
results = []
- while start 1:
fuseCoppers = True
objs = []
- objs.append(self.makeBoard(prefix=None,thickness=board_thickness))
-
- coppers = self.makeCoppers(shape_type='solid',holes=True,prefix=None,
- fit_arcs=fit_arcs,thickness=copper_thickness,fuse=fuseCoppers,
- board_thickness=board_thickness)
+ objs.append(self.makeBoard(prefix=None, thickness=board_thickness))
+
+ coppers = self.makeCoppers(
+ shape_type="solid",
+ holes=True,
+ prefix=None,
+ fit_arcs=fit_arcs,
+ thickness=copper_thickness,
+ fuse=fuseCoppers,
+ board_thickness=board_thickness,
+ )
if coppers:
if not fuseCoppers:
@@ -2894,42 +2919,40 @@ def make(self,copper_thickness=0.05,fit_arcs=True,load_parts=False,
layer = self.layer
try:
self.layer = None
- if combo > 1:
- objs = self._makeFuse(objs,'pcb')
- else:
- objs = self._makeCompound(objs,'pcb')
+ objs = self._makeFuse(objs, "pcb") if combo > 1 else self._makeCompound(objs, "pcb")
if self.add_feature and load_parts:
- try:
+ with contextlib.suppress(Exception):
objs.ViewObject.SelectionStyle = 1
- except Exception:
- pass
finally:
self.setLayer(layer)
- self._popLog('all done')
- fitView();
+ self._popLog("all done")
+ fitView()
return objs
+
def getTestFile(name):
import glob
+
if not os.path.exists(name):
path = os.path.dirname(os.path.abspath(__file__))
- path = os.path.join(path,'tests')
+ path = os.path.join(path, "tests")
if name:
- path = os.path.join(path,name)
+ path = os.path.join(path, name)
else:
path = name
if os.path.isdir(path):
- return glob.glob(os.path.join(path,'*.kicad_pcb'))
+ return glob.glob(os.path.join(path, "*.kicad_pcb"))
if os.path.isfile(path):
return [path]
- path += '.kicad_pcb'
+ path += ".kicad_pcb"
if os.path.isfile(path):
return [path]
- raise RuntimeError('Cannot find {}'.format(name))
+ raise RuntimeError(f"Cannot find {name}")
-def test(names=''):
- if not isinstance(names,(tuple,list)):
+
+def test(names=""):
+ if not isinstance(names, (tuple, list)):
names = [names]
files = set()
for name in names:
@@ -2940,4 +2963,3 @@ def test(names=''):
pcb.make(fuseCoppers=True)
pcb.add_feature = False
Part.show(pcb.make())
-
diff --git a/ksu_locator.py b/ksu_locator.py
index 58e7ebc..f40d41d 100644
--- a/ksu_locator.py
+++ b/ksu_locator.py
@@ -1,23 +1,24 @@
-# -*- coding: utf-8 -*-
-#****************************************************************************
-#* *
-#* Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
-#* 3D exporter for FreeCAD *
-#* Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
-#* Copyright (c) 2015 *
-#* Maurice easyw@katamail.com *
-#* *
-#* Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
-#* *
+# ****************************************************************************
+# * *
+# * Kicad STEPUP (TM) (3D kicad board and models to STEP) for FreeCAD *
+# * 3D exporter for FreeCAD *
+# * Kicad STEPUP TOOLS (TM) (3D kicad board and models to STEP) for FreeCAD *
+# * Copyright (c) 2015 *
+# * Maurice easyw@katamail.com *
+# * *
+# * Kicad STEPUP (TM) is a TradeMark and cannot be freely usable *
+# * *
-import os, sys
+import os
+
def module_path():
- #return os.path.dirname(unicode(__file__, encoding))
+ # return os.path.dirname(unicode(__file__, encoding))
return os.path.dirname(__file__)
-
+
+
def abs_module_path():
- #return os.path.dirname(unicode(__file__, encoding))
- #return os.path.dirname(__file__)
+ # return os.path.dirname(unicode(__file__, encoding))
+ # return os.path.dirname(__file__)
return os.path.realpath(__file__)
diff --git a/makefacedxf.py b/makefacedxf.py
index 16b25af..04d846b 100644
--- a/makefacedxf.py
+++ b/makefacedxf.py
@@ -1,5 +1,3 @@
-# -*- coding: utf-8 -*-
-
# Form implementation generated from reading ui file 'C:\Cad\Progetti_K\3D-FreeCad-tools\explode.ui'
#
# Created: Fri Sep 21 14:09:48 2018
@@ -7,126 +5,135 @@
#
# WARNING! All changes made in this file will be lost!
-import FreeCAD, FreeCADGui, os, Part
+import os
+
+import FreeCAD
+import FreeCADGui
+import Part
import PySide
-from PySide import QtGui, QtCore
+from PySide import QtGui
+
QtWidgets = QtGui
-from sys import platform as _platform
-import sys,os
import time
+
global copper_diffuse, silks_diffuse, silks_version, use_dxf_internal
use_dxf_internal = True
global use_AppPart, use_Links, use_LinkGroups
-use_AppPart=False # False
-use_Links=False
+use_AppPart = False # False
+use_Links = False
global FC_export_min_version
-FC_export_min_version="11670" #11670 latest JM
-silks_version = '1.5'
+FC_export_min_version = "11670" # 11670 latest JM
+silks_version = "1.5"
use_LinkGroups = False
-if 'LinkView' in dir(FreeCADGui):
+if "LinkView" in dir(FreeCADGui):
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if prefs.GetBool('asm3_linkGroups'):
+ if prefs.GetBool("asm3_linkGroups"):
use_LinkGroups = True
- use_Links=True #False
- #print('using \'LinkGroups\' and \'Links\'')
- elif prefs.GetBool('asm3_links'):
- use_Links=True #False
- #print('using \'Part\' container and \'Links\'')
+ use_Links = True # False
+ # print('using \'LinkGroups\' and \'Links\'')
+ elif prefs.GetBool("asm3_links"):
+ use_Links = True # False
+ # print('using \'Part\' container and \'Links\'')
else:
use_LinkGroups = False
- #print('using \'Part\' container')
+ # print('using \'Part\' container')
else:
use_LinkGroups = False
- #print('using \'Part\' container')
-#
+ # print('using \'Part\' container')
+
+
def getFCversion():
- FC_majorV=int(float(FreeCAD.Version()[0]))
- FC_minorV=int(float(FreeCAD.Version()[1]))
+ FC_majorV = int(float(FreeCAD.Version()[0]))
+ FC_minorV = int(float(FreeCAD.Version()[1]))
try:
- FC_git_Nbr=int (float(FreeCAD.Version()[2].strip(" (Git)").split(' ')[0])) #+int(FreeCAD.Version()[2].strip(" (Git)").split(' ')[1])
+ FC_git_Nbr = int(
+ float(FreeCAD.Version()[2].strip(" (Git)").split(" ")[0]),
+ ) # +int(FreeCAD.Version()[2].strip(" (Git)").split(' ')[1])
except:
- FC_git_Nbr=0
- return FC_majorV,FC_minorV,FC_git_Nbr
-
-FC_majorV,FC_minorV,FC_git_Nbr=getFCversion()
-FreeCAD.Console.PrintWarning('FC Version '+str(FC_majorV)+str(FC_minorV)+"-"+str(FC_git_Nbr)+'\n')
-if FC_majorV == 0 and FC_minorV == 17:
- if FC_git_Nbr >= int(FC_export_min_version):
- use_AppPart=True
-#if FreeCAD.Version()[2] == 'Unknown': #workaround for local building
+ FC_git_Nbr = 0
+ return FC_majorV, FC_minorV, FC_git_Nbr
+
+
+FC_majorV, FC_minorV, FC_git_Nbr = getFCversion()
+FreeCAD.Console.PrintWarning("FC Version " + str(FC_majorV) + str(FC_minorV) + "-" + str(FC_git_Nbr) + "\n")
+if FC_majorV == 0 and FC_minorV == 17 and FC_git_Nbr >= int(FC_export_min_version):
+ use_AppPart = True
+# if FreeCAD.Version()[2] == 'Unknown': #workaround for local building
# use_AppPart=True
if FC_majorV > 0:
- use_AppPart=True
+ use_AppPart = True
if FC_majorV == 0 and FC_minorV > 17:
- #if FC_git_Nbr >= int(FC_export_min_version):
- use_AppPart=True
+ # if FC_git_Nbr >= int(FC_export_min_version):
+ use_AppPart = True
+
def crc_gen_d(data):
import binascii
import re
-
- #data=u'Würfel'
- content=re.sub(r'[^\x00-\x7F]+','_', data)
- #make_unicode(hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
- #hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:].encode('utf-8')
- #print(data +u'_'+ hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
- return u'_'+ make_unicode_d(hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
+
+ # data=u'Würfel'
+ content = re.sub(r"[^\x00-\x7F]+", "_", data)
+ # make_unicode(hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
+ # hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:].encode('utf-8')
+ # print(data +u'_'+ hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
+ return "_" + make_unicode_d(hex(binascii.crc_hqx(content.encode("utf-8"), 0x0000))[2:])
+
+
##
+
def make_unicode_d(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.decode('utf-8')
- return input
- else: #py2
- if type(input) != unicode:
- input = input.decode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.decode("utf-8")
+ if type(input) != unicode:
+ return input.decode("utf-8")
+ return input
+
def find_pcb_name():
- #searching for a pcb
- pcb_name = ''
+ # searching for a pcb
+ pcb_name = ""
for o in FreeCAD.ActiveDocument.Objects:
- if 'Pcb' in o.Label:
- pcb_name=o.Name
+ if "Pcb" in o.Label:
+ pcb_name = o.Name
break
return pcb_name
+
def say(msg):
FreeCAD.Console.PrintMessage(msg)
- FreeCAD.Console.PrintMessage('\n')
+ FreeCAD.Console.PrintMessage("\n")
+
-metal_copper="""material DEF MET-COPPER Material {
+metal_copper = """material DEF MET-COPPER Material {
ambientIntensity 0.022727
diffuseColor 0.7038 0.27048 0.0828
specularColor 0.780612 0.37 0.000000
emissiveColor 0.000000 0.000000 0.000000
shininess 0.2
transparency 0.0
- }"""
+ }"""
copper_diffuse = (0.7038, 0.27048, 0.0828)
-silks_diffuse = (0.98,0.92,0.84)
+silks_diffuse = (0.98, 0.92, 0.84)
# Name Ambient Diffuse Specular Shininess
# brass 0.329412 0.223529 0.027451 0.780392 0.568627 0.113725 0.992157 0.941176 0.807843 0.21794872
-brass_diffuse = (0.780392,0.568627,0.113725)
+brass_diffuse = (0.780392, 0.568627, 0.113725)
-def simple_cpy (obj,lbl):
- copy = FreeCAD.ActiveDocument.addObject('Part::Feature',obj.Name)
+
+def simple_cpy(obj, lbl):
+ copy = FreeCAD.ActiveDocument.addObject("Part::Feature", obj.Name)
copy.Label = lbl
copy.Shape = obj.Shape
- copy.ViewObject.ShapeColor = obj.ViewObject.ShapeColor
- copy.ViewObject.LineColor = obj.ViewObject.LineColor
- copy.ViewObject.PointColor = obj.ViewObject.PointColor
+ copy.ViewObject.ShapeColor = obj.ViewObject.ShapeColor
+ copy.ViewObject.LineColor = obj.ViewObject.LineColor
+ copy.ViewObject.PointColor = obj.ViewObject.PointColor
copy.ViewObject.DiffuseColor = obj.ViewObject.DiffuseColor
return copy
@@ -134,54 +141,62 @@ def simple_cpy (obj,lbl):
if not use_dxf_internal:
import importDXF
else:
- from dxf_parser import _importDXF
-from kicadStepUptools import make_unicode, make_string
+ pass
+from kicadStepUptools import make_string, make_unicode
+
def makeFaceDXF():
global copper_diffuse, silks_diffuse, use_dxf_internal
global use_LinkGroups, use_AppPart, silks_version
- import _DXF_Import
from dxf_parser import _importDXF
-
- FreeCAD.Console.PrintMessage('SilkS version: '+silks_version+'\n')
- doc=FreeCAD.ActiveDocument
+ FreeCAD.Console.PrintMessage("SilkS version: " + silks_version + "\n")
+
+ doc = FreeCAD.ActiveDocument
if doc is None:
FreeCAD.newDocument()
- doc=FreeCAD.ActiveDocument
- docG=FreeCADGui.ActiveDocument
- Filter=""
- last_pcb_path=""
+ doc = FreeCAD.ActiveDocument
+ docG = FreeCADGui.ActiveDocument
+ last_pcb_path = ""
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
last_pcb_path = pg.GetString("last_pcb_path")
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- #print('native_dlg',prefs_.GetBool('native_dlg'))
- if not(prefs_.GetBool('not_native_dlg')):
- fn, Filter = PySide.QtGui.QFileDialog.getOpenFileNames(None, "Open File...",
- make_unicode(last_pcb_path), "*.dxf")
+ # print('native_dlg',prefs_.GetBool('native_dlg'))
+ if not (prefs_.GetBool("not_native_dlg")):
+ fn, _Filter = PySide.QtGui.QFileDialog.getOpenFileNames(
+ None,
+ "Open File...",
+ make_unicode(last_pcb_path),
+ "*.dxf",
+ )
else:
- fn, Filter = PySide.QtGui.QFileDialog.getOpenFileNames(None, "Open File...",
- make_unicode(last_pcb_path), "*.dxf",options=QtWidgets.QFileDialog.DontUseNativeDialog)
+ fn, _Filter = PySide.QtGui.QFileDialog.getOpenFileNames(
+ None,
+ "Open File...",
+ make_unicode(last_pcb_path),
+ "*.dxf",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
for fname in fn:
- path, name = os.path.split(fname)
- filename=os.path.splitext(name)[0]
- say("filename = "+str(filename))
- #importDXF.open(os.path.join(dirname,filename))
+ _path, name = os.path.split(fname)
+ filename = os.path.splitext(name)[0]
+ say("filename = " + str(filename))
+ # importDXF.open(os.path.join(dirname,filename))
if len(fname) > 0:
- #importDXF.open(fname)
- last_pcb_path=os.path.dirname(fname)
- ftname_sfx=crc_gen_d(make_unicode_d(filename))
+ # importDXF.open(fname)
+ last_pcb_path = os.path.dirname(fname)
+ ftname_sfx = crc_gen_d(make_unicode_d(filename))
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- pg.SetString("last_pcb_path", make_string(last_pcb_path)) # py3 .decode("utf-8")
+ pg.SetString("last_pcb_path", make_string(last_pcb_path)) # py3 .decode("utf-8")
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- pcb_color_pos = pg.GetInt('pcb_color')
- #print(pcb_color_pos)
+ pcb_color_pos = pg.GetInt("pcb_color")
+ # print(pcb_color_pos)
if pcb_color_pos == 9:
- silks_diffuse = (0.18,0.18,0.18) #slick black
+ silks_diffuse = (0.18, 0.18, 0.18) # slick black
else:
- silks_diffuse = (0.98,0.92,0.84) # #antique white # white (0.906,0.906,0.910)
- doc=FreeCAD.ActiveDocument
+ silks_diffuse = (0.98, 0.92, 0.84) # #antique white # white (0.906,0.906,0.910)
+ doc = FreeCAD.ActiveDocument
objects = []
say("loading... ")
t = time.time()
@@ -194,144 +209,141 @@ def makeFaceDXF():
say("Legacy internal DXF importer 1")
_importDXF.insert(fname, doc.Name, forcePrefs=True)
# _DXF_Import.insert(fname, doc.Name)
-
+
+ elif not use_dxf_internal:
+ importDXF.open(fname)
else:
- if not use_dxf_internal:
- importDXF.open(fname)
- else:
- say("Legacy internal DXF importer 2")
- _importDXF.open(fname,forcePrefs=True)
- # _DXF_Import.open(fname)
+ say("Legacy internal DXF importer 2")
+ _importDXF.open(fname, forcePrefs=True)
+ # _DXF_Import.open(fname)
imp_objects = []
if doc is not None:
for o in doc.Objects:
if o.Name not in str(objects):
- if hasattr(o, 'Shape'):
+ if hasattr(o, "Shape"):
imp_objects.append(o)
else:
FreeCAD.ActiveDocument.removeObject(o.Name)
FreeCADGui.SendMsgToActiveView("ViewFit")
timeP = time.time() - t
- say("loading time = "+str(timeP) + "s")
- #print(imp_objects)
- using_connect=False #both connect and Part::FaceMakerBullseye take the same time in bulding a face
+ say("loading time = " + str(timeP) + "s")
+ # print(imp_objects)
+ using_connect = False # both connect and Part::FaceMakerBullseye take the same time in bulding a face
if using_connect:
import BOPTools.JoinFeatures
- j = BOPTools.JoinFeatures.makeConnect(name='Connect')
+
+ j = BOPTools.JoinFeatures.makeConnect(name="Connect")
j.Objects = imp_objects
j.Proxy.execute(j)
j.purgeTouched()
for obj in j.ViewObject.Proxy.claimChildren():
obj.ViewObject.hide()
- doc.addObject("Part::Face", "fc").Sources = (FreeCAD.ActiveDocument.getObject(j.Name), )
+ doc.addObject("Part::Face", "fc").Sources = (FreeCAD.ActiveDocument.getObject(j.Name),)
doc.recompute()
- c=doc.ActiveObject
+ c = doc.ActiveObject
imp_objects.append(j)
imp_objects.append(c)
- f=c.Shape
- #stop
- else: #if use_dxf_internal: # not(checkDXFsettings(True)):
+ f = c.Shape
+ # stop
+ else: # if use_dxf_internal: # not(checkDXFsettings(True)):
try:
say("standard DXF importer [Part::FaceMakerBullseye]")
- edges=[]
- sorted_edges=[]
- w=[]
+ w = []
# edges=sum((obj.Shape.Edges for obj in \
# imp_objects if hasattr(obj,'Shape')),[])
for o in imp_objects:
- if hasattr(o,'Shape'):
+ if hasattr(o, "Shape"):
w1 = Part.Wire(Part.__sortEdges__(o.Shape.Edges))
w.append(w1)
- #print (w)
- f=Part.makeFace(w,'Part::FaceMakerBullseye')
- except Part.OCCError: # Exception: #
- # FreeCAD.Console.PrintError('Error in source %s (%s)' % (faceobj.Name,faceobj.Label)+"\n")
- FreeCAD.Console.PrintError('Error in source %s (%s)' % (f.Name,f.Label)+"\n")
-
- #stop
- for o in imp_objects: #doc.Objects:
+ # print (w)
+ f = Part.makeFace(w, "Part::FaceMakerBullseye")
+ except Part.OCCError: # Exception: #
+ FreeCAD.Console.PrintError("Error in source face" + "\n")
+
+ # stop
+ for o in imp_objects: # doc.Objects:
# if o.Name not in str(objects):
- doc.removeObject(o.Name)
- if 'Silk' in filename:
- layerName = 'Silks'
- else:
- layerName = 'Tracks'
- if 'F.Silk' in filename or 'F_Silk' in filename:
- layerName = 'top'+layerName
- elif 'B.Silk' in filename or 'B_Silk' in filename:
- layerName = 'bot'+layerName
- elif 'F.' in filename or 'F_' in filename:
- layerName = 'top'+layerName
- elif 'B.' in filename or 'B_' in filename:
- layerName = 'bot'+layerName
-
- doc.addObject('Part::Feature',layerName+ftname_sfx).Shape=f # +'tmp').Shape=f
- newShape=doc.ActiveObject
+ doc.removeObject(o.Name)
+ layerName = "Silks" if "Silk" in filename else "Tracks"
+ if "F.Silk" in filename or "F_Silk" in filename:
+ layerName = "top" + layerName
+ elif "B.Silk" in filename or "B_Silk" in filename:
+ layerName = "bot" + layerName
+ elif "F." in filename or "F_" in filename:
+ layerName = "top" + layerName
+ elif "B." in filename or "B_" in filename:
+ layerName = "bot" + layerName
+
+ doc.addObject("Part::Feature", layerName + ftname_sfx).Shape = f # +'tmp').Shape=f
+ newShape = doc.ActiveObject
# newShape.Label = layerName+ftname_sfx
# doc.recompute(None,True,True)
botOffset = 1.6
- if 'Silk' in layerName:
+ if "Silk" in layerName:
docG.getObject(newShape.Name).ShapeColor = silks_diffuse
else:
- docG.getObject(newShape.Name).ShapeColor = brass_diffuse #copper_diffuse #(0.78,0.56,0.11)
- del f # memory leak?
- del imp_objects #memory leak?
+ docG.getObject(newShape.Name).ShapeColor = brass_diffuse # copper_diffuse #(0.78,0.56,0.11)
+ del f # memory leak?
+ del imp_objects # memory leak?
pcb_name = find_pcb_name()
# new_obj = simple_cpy(newShape,layerName+ftname_sfx)
# doc.removeObject(newShape.Name)
# newShape = new_obj
- if len (doc.getObjectsByLabel(pcb_name)) > 0:
+ if len(doc.getObjectsByLabel(pcb_name)) > 0:
### shifting placement to be removed if dxf is exported with drill place file origin
newShape.Placement = doc.getObjectsByLabel(pcb_name)[0].Placement
- #botTracks.Placement = doc.Pcb.Placement
- board_geom_name='Board_Geoms'+pcb_name[pcb_name.rfind('_'):]
- if len (doc.getObjectsByLabel(board_geom_name)) > 0:
+ # botTracks.Placement = doc.Pcb.Placement
+ board_geom_name = "Board_Geoms" + pcb_name[pcb_name.rfind("_") :]
+ if len(doc.getObjectsByLabel(board_geom_name)) > 0:
if use_AppPart and not use_LinkGroups:
doc.getObject(board_geom_name).addObject(newShape)
elif use_LinkGroups:
- doc.getObject(board_geom_name).ViewObject.dropObject(newShape,None,'',[])
- if hasattr(doc.getObjectsByLabel(pcb_name)[0], 'Shape'):
+ doc.getObject(board_geom_name).ViewObject.dropObject(newShape, None, "", [])
+ if hasattr(doc.getObjectsByLabel(pcb_name)[0], "Shape"):
botOffset = doc.getObjectsByLabel(pcb_name)[0].Shape.BoundBox.ZLength
else:
botOffset = doc.getObjectsByLabel(pcb_name)[0].OutList[1].Shape.BoundBox.ZLength
- #elif 'bot' in layerName:
+ # elif 'bot' in layerName:
# newShape.Placement.Base.z-=1.6
- if 'top' in layerName:
- newShape.Placement.Base.z+=0.07
- if 'bot' in layerName:
- newShape.Placement.Base.z-=botOffset+0.07
+ if "top" in layerName:
+ newShape.Placement.Base.z += 0.07
+ if "bot" in layerName:
+ newShape.Placement.Base.z -= botOffset + 0.07
timeD = time.time() - t - timeP
- say("displaying time = "+str(timeD) + "s")
+ say("displaying time = " + str(timeD) + "s")
FreeCADGui.SendMsgToActiveView("ViewFit")
# doc.recompute(None,True,True)
- #docG.activeView().viewAxonometric()
+ # docG.activeView().viewAxonometric()
docG.activeView().viewTop()
+
+
##
def checkDXFsettings(leg=None):
-
+
pgD = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
dxfLI = pgD.GetBool("dxfUseLegacyImporter")
dxfJG = pgD.GetBool("joingeometry")
dxfCP = pgD.GetBool("dxfCreatePart")
checkResult = True
- #FreeCAD.Console.PrintMessage (dxfLI);FreeCAD.Console.PrintMessage (dxfJG); FreeCAD.Console.PrintMessage (dxfCP)
- if not dxfLI:
- FreeCAD.Console.PrintError('DXF Legacy Importer NOT selected A\n')
+ # FreeCAD.Console.PrintMessage (dxfLI);FreeCAD.Console.PrintMessage (dxfJG); FreeCAD.Console.PrintMessage (dxfCP)
+ if not dxfLI:
+ FreeCAD.Console.PrintError("DXF Legacy Importer NOT selected A\n")
# checkResult = False #enabling new DXFImporter also
- if dxfLI and (leg == True): # not dxfLI: enabling new DXFImporter also
- FreeCAD.Console.PrintMessage('DXF Legacy Importer selected\n')
+ if dxfLI and (leg): # not dxfLI: enabling new DXFImporter also
+ FreeCAD.Console.PrintMessage("DXF Legacy Importer selected\n")
# checkResult = False
return True
- if not(dxfLI) and (leg == True): # not dxfLI: enabling new DXFImporter also
- FreeCAD.Console.PrintMessage('DXF Legacy Importer NOT selected B\n')
+ if not (dxfLI) and (leg): # not dxfLI: enabling new DXFImporter also
+ FreeCAD.Console.PrintMessage("DXF Legacy Importer NOT selected B\n")
# checkResult = False
return True
if not dxfJG:
- FreeCAD.Console.PrintError('DXF Join Geometries NOT selected\n')
+ FreeCAD.Console.PrintError("DXF Join Geometries NOT selected\n")
checkResult = False
if not dxfCP:
- FreeCAD.Console.PrintError('DXF Create Simple Part Shapes NOT selected\n')
+ FreeCAD.Console.PrintError("DXF Create Simple Part Shapes NOT selected\n")
checkResult = False
return checkResult
-
-#makeFaceDXF()
+
+
+# makeFaceDXF()
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..056165c
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,122 @@
+[tool.ruff]
+line-length = 120
+target-version = "py311"
+exclude = ["fcad_parser", "dxf_parser"]
+
+[tool.ruff.lint]
+select = [
+ "F", # Pyflakes — errors
+ "E", # Pycodestyle — errors
+ "W", # Pycodestyle — warnings
+ "I", # isort (native ruff)
+ "UP", # pyupgrade — modernise syntax
+ "SIM", # Simplify expressions
+ "RUF", # Ruff-specific rules
+ "PL", # Pylint rules
+ "BLE", # Blind except
+ "PIE", # Misc pie rules
+ "RET", # Return
+ "C4", # Comprehensions
+ "RSE", # Raise
+ "SLF", # Self/private
+ "FLY", # Flynt — f-string conversion
+ "NPY", # NumPy rules
+ "ICN", # Import conventions
+ "PERF", # Performance
+ "T10", # Debugger statements
+ "TID", # Tidy imports
+ "TRY", # Try/except patterns
+ "YTT", # sys.version_info checks
+]
+ignore = [
+ "E402",
+ "E501",
+ "E722",
+ "E721",
+ "E902",
+ "E741",
+ "F403", "F405", "F821",
+ "PLR0911", "PLR0912", "PLR0913", "PLR0914", "PLR0915",
+ "PLR2004",
+ "PLW0602", "PLW0603", "PLW0604",
+ "PLC0415",
+ "PLW2901",
+ "PLW0127",
+ "PLC0205",
+ "BLE001",
+ "SLF001",
+ "T201",
+ "PERF401",
+ "TRY002", "TRY003", "TRY300", "TRY301",
+ "SIM102", "SIM108", "SIM115",
+]
+extend-fixable = ["SIM103", "SIM101", "C416", "C419"]
+
+[tool.ruff.lint.per-file-ignores]
+"test*.py" = ["T20"]
+"makefacedxf.py" = ["RUF001", "RUF003"]
+"fcad_parser/**" = ["ALL"]
+"dxf_parser/**" = ["ALL"]
+
+[tool.ruff.format]
+quote-style = "double"
+indent-style = "space"
+line-ending = "auto"
+
+[tool.uv]
+required-version = ">=0.5"
+
+[tool.ty]
+
+[tool.ty.environment]
+python-version = "3.11"
+
+[tool.ty.src]
+exclude = [
+ "fcad_parser",
+ "dxf_parser",
+ "demo",
+ "images",
+ "Resources",
+ "translations",
+ "*.gif",
+ "*.pdf",
+ "*.dxf",
+ "*.FCStd",
+ "*.stp",
+ ".github",
+]
+
+[tool.ty.analysis]
+replace-imports-with-any = [
+ "FreeCAD",
+ "FreeCADGui",
+ "Part",
+ "Draft",
+ "Mesh",
+ "PySide",
+ "PySide.QtGui",
+ "PySide.QtCore",
+ "PySide.QtWidgets",
+ "pivy",
+]
+allowed-unresolved-imports = [
+ "FreeCAD",
+ "FreeCADGui",
+ "Part",
+ "Draft",
+ "Mesh",
+ "PySide",
+ "PySide.QtGui",
+ "PySide.QtCore",
+ "PySide.QtWidgets",
+ "pivy",
+ "fcad_parser.**",
+ "dxf_parser.**",
+]
+
+[tool.ty.rules]
+all = "ignore"
+unused-ignore-comment = "warn"
+
+
diff --git a/selection2edges.py b/selection2edges.py
index df51c25..5598a09 100644
--- a/selection2edges.py
+++ b/selection2edges.py
@@ -1,94 +1,130 @@
import Draft
+import FreeCAD
+import FreeCADGui
import numpy as np
-import FreeCAD, FreeCADGui, Part
+import Part
+
def sel2edges():
tol = 0.000000001
- delete=False
- mk_sketch=True
-
- rh_edges=[]
- rh_edges_names=[]
- rh_obj_name=[]
- rh_obj=[]
- eobj_list=[]
- selEx=FreeCADGui.Selection.getSelectionEx()
- doc=FreeCAD.ActiveDocument
- if len (selEx) > 0:
- doc.openTransaction('ed2sk')
+ delete = False
+ mk_sketch = True
+
+ rh_edges = []
+ rh_edges_names = []
+ rh_obj_name = []
+ rh_obj = []
+ eobj_list = []
+ selEx = FreeCADGui.Selection.getSelectionEx()
+ doc = FreeCAD.ActiveDocument
+ if len(selEx) > 0:
+ doc.openTransaction("ed2sk")
for selEdge in selEx:
- for i,e in enumerate(selEdge.SubObjects):
+ for i, e in enumerate(selEdge.SubObjects):
rh_edges.append(e)
- rh_edges_names.append(selEdge.ObjectName+'.'+selEdge.SubElementNames[i])
+ rh_edges_names.append(selEdge.ObjectName + "." + selEdge.SubElementNames[i])
rh_obj.append(selEdge.Object)
rh_obj_name.append(selEdge.ObjectName)
Part.show(e)
- eobj=doc.ActiveObject
+ eobj = doc.ActiveObject
eobj_list.append(eobj)
doc.recompute()
for e in rh_edges_names:
print(e)
- doc.addObject("Part::Compound","Compound")
- cmp=doc.ActiveObject
+ doc.addObject("Part::Compound", "Compound")
+ cmp = doc.ActiveObject
cmp.Links = eobj_list
doc.recompute()
-
+
active_view = FreeCADGui.ActiveDocument.activeView()
- rotation_view = active_view.getCameraOrientation()
- view_direction = active_view.getViewDirection()
-
- def placement_tol(vect1,vect2,tol):
- ''' 1 if tolerance of placement is low '''
- r=abs(np.subtract(vect1, vect2))
+ active_view.getCameraOrientation()
+ active_view.getViewDirection()
+
+ def placement_tol(vect1, vect2, tol):
+ """1 if tolerance of placement is low"""
+ r = abs(np.subtract(vect1, vect2))
if np.sum(r > tol):
return 0
- else:
- return 1
-
- if placement_tol(FreeCADGui.ActiveDocument.activeView().getViewDirection(),FreeCAD.Vector(1.0, 0.0, 0.0),tol):
- print('left')
+ return 1
+
+ if placement_tol(FreeCADGui.ActiveDocument.activeView().getViewDirection(), FreeCAD.Vector(1.0, 0.0, 0.0), tol):
+ print("left")
# sv = Draft.makeShape2DView(cmp, FreeCAD.Vector(-1.0, 0.0, 0.0))
sv = Draft.make_shape2dview(cmp, FreeCAD.Vector(-1.0, -0.0, -0.0))
doc.recompute()
- cmp.ViewObject.Visibility=False
- sv.Placement=FreeCAD.Placement(FreeCAD.Vector(0,0,0), FreeCAD.Rotation(FreeCAD.Vector(0,1,0),90), FreeCAD.Vector(0,0,0)).multiply(sv.Placement)
+ cmp.ViewObject.Visibility = False
+ sv.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, 0, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 1, 0), 90),
+ FreeCAD.Vector(0, 0, 0),
+ ).multiply(sv.Placement)
doc.recompute()
- sv.Placement=FreeCAD.Placement(FreeCAD.Vector(0,0,0), FreeCAD.Rotation(FreeCAD.Vector(0,0,1),180), FreeCAD.Vector(0,0,0)).multiply(sv.Placement)
- elif placement_tol(FreeCADGui.ActiveDocument.activeView().getViewDirection(), FreeCAD.Vector(-1.0, 0.0, 0.0),tol):
- print('right')
+ sv.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, 0, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 180),
+ FreeCAD.Vector(0, 0, 0),
+ ).multiply(sv.Placement)
+ elif placement_tol(
+ FreeCADGui.ActiveDocument.activeView().getViewDirection(),
+ FreeCAD.Vector(-1.0, 0.0, 0.0),
+ tol,
+ ):
+ print("right")
sv = Draft.make_shape2dview(cmp, FreeCAD.Vector(1.0, 0.0, 0.0))
- cmp.ViewObject.Visibility=False
+ cmp.ViewObject.Visibility = False
doc.recompute()
- sv.Placement=FreeCAD.Placement(FreeCAD.Vector(0,0,0), FreeCAD.Rotation(FreeCAD.Vector(0,1,0),-90), FreeCAD.Vector(0,0,0)).multiply(sv.Placement)
+ sv.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, 0, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 1, 0), -90),
+ FreeCAD.Vector(0, 0, 0),
+ ).multiply(sv.Placement)
doc.recompute()
- sv.Placement=FreeCAD.Placement(FreeCAD.Vector(0,0,0), FreeCAD.Rotation(FreeCAD.Vector(0,0,1),180), FreeCAD.Vector(0,0,0)).multiply(sv.Placement)
- elif placement_tol(FreeCADGui.ActiveDocument.activeView().getViewDirection(), FreeCAD.Vector(0.0, 0.0, -1.0),tol):
- print('top')
+ sv.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, 0, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), 180),
+ FreeCAD.Vector(0, 0, 0),
+ ).multiply(sv.Placement)
+ elif placement_tol(
+ FreeCADGui.ActiveDocument.activeView().getViewDirection(),
+ FreeCAD.Vector(0.0, 0.0, -1.0),
+ tol,
+ ):
+ print("top")
sv = Draft.make_shape2dview(cmp, FreeCAD.Vector(0.0, 0.0, 1.0))
- cmp.ViewObject.Visibility=False
+ cmp.ViewObject.Visibility = False
doc.recompute()
- elif placement_tol(FreeCADGui.ActiveDocument.activeView().getViewDirection(), FreeCAD.Vector(0.0, 0.0, 1.0),tol):
- print('bottom')
+ elif placement_tol(
+ FreeCADGui.ActiveDocument.activeView().getViewDirection(),
+ FreeCAD.Vector(0.0, 0.0, 1.0),
+ tol,
+ ):
+ print("bottom")
sv = Draft.make_shape2dview(cmp, FreeCAD.Vector(-0.0, -0.0, -1.0))
- cmp.ViewObject.Visibility=False
+ cmp.ViewObject.Visibility = False
doc.recompute()
- sv.Placement=FreeCAD.Placement(FreeCAD.Vector(0,0,0), FreeCAD.Rotation(FreeCAD.Vector(0,1,0),180), FreeCAD.Vector(0,0,0)).multiply(sv.Placement)
+ sv.Placement = FreeCAD.Placement(
+ FreeCAD.Vector(0, 0, 0),
+ FreeCAD.Rotation(FreeCAD.Vector(0, 1, 0), 180),
+ FreeCAD.Vector(0, 0, 0),
+ ).multiply(sv.Placement)
else:
- FreeCAD.Console.PrintWarning('This tool works only on front, rear, top, bot, left, right views')
- mk_sketch=False
+ FreeCAD.Console.PrintWarning("This tool works only on front, rear, top, bot, left, right views")
+ mk_sketch = False
doc.recompute()
if mk_sketch:
FreeCADGui.Selection.clearSelection()
- FreeCADGui.Selection.addSelection(doc.Name,sv.Name)
- sk = Draft.makeSketch(sv, autoconstraints=False, delete=False) #, radiusPrecision=0)
- sv.ViewObject.Visibility=False
+ FreeCADGui.Selection.addSelection(doc.Name, sv.Name)
+ sk = Draft.makeSketch(sv, autoconstraints=False, delete=False) # , radiusPrecision=0)
+ sv.ViewObject.Visibility = False
FreeCADGui.Selection.clearSelection()
- FreeCADGui.Selection.addSelection(doc.Name,sk.Name)
+ FreeCADGui.Selection.addSelection(doc.Name, sk.Name)
if delete:
doc.removeObject(cmp.Name)
for o in eobj_list:
doc.removeObject(o.Name)
doc.recompute()
doc.commitTransaction()
-# end
\ No newline at end of file
+
+
+# end
diff --git a/step_amend.py b/step_amend.py
index 87a5a8e..a1d05af 100644
--- a/step_amend.py
+++ b/step_amend.py
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
# ****************************************************************************
# * Copyright (c) 2018 Maurice *
# * *
@@ -14,99 +13,98 @@
# import FreeCAD
# import FreeCADGui
-import shutil
+
+# support both gz and zipfile archives
+# Catia seems to use gz, Inventor zipfile
+# improved import, open and export
+import gzip as gz
import os
import re
+import shutil
+
# import ImportGui
# import PySide
# from PySide import QtCore
# from PySide import QtGui
import tempfile
-import sys
-
-# support both gz and zipfile archives
-# Catia seems to use gz, Inventor zipfile
-# improved import, open and export
-
-
-import gzip as gz
-import builtins
-import importlib
-import io
-
import zipfile as zf
__version__ = "1.0.0"
+
def transp_rmv(filename):
-
+
# sayz(filename)
- found_transp_issue=False
+ found_transp_issue = False
ext = os.path.splitext(os.path.basename(filename))[1]
fname = os.path.splitext(os.path.basename(filename))[0]
basepath = os.path.split(filename)[0]
- if 'stpz' in ext.lower():
- filepath = os.path.join(basepath, fname + ".stp")
+ if "stpz" in ext.lower():
+ os.path.join(basepath, fname + ".stp")
tempdir = tempfile.gettempdir() # get the current temporary directory
tempfilepath = os.path.join(tempdir, fname + ".stp")
- if 0: # zf.is_zipfile(filename):
+ if 0: # zf.is_zipfile(filename):
with zf.ZipFile(filename, "r") as fz:
file_names = fz.namelist()
for fn in file_names:
# sayz(fn)
# with fz.open(fn) as zfile:
- fiz_content=[]
+ fiz_content = []
with fz.open(fn) as fiz:
- # with open(fn, "rb") as fiz:
+ # with open(fn, "rb") as fiz:
for line in fiz:
- if (b'SURFACE_STYLE_TRANSPARENT(1.);' in line):
- line = re.sub(b'SURFACE_STYLE_TRANSPARENT\(1.\)',b'SURFACE_STYLE_TRANSPARENT(0.)',line)
+ if b"SURFACE_STYLE_TRANSPARENT(1.);" in line:
+ line = re.sub(
+ rb"SURFACE_STYLE_TRANSPARENT\(1.\)",
+ b"SURFACE_STYLE_TRANSPARENT(0.)",
+ line,
+ )
fiz_content.append(line)
- #foz.writestr(line)
- #with zf.ZipFile(filename, "w") as foz:
+ # foz.writestr(line)
+ # with zf.ZipFile(filename, "w") as foz:
with zf.ZipFile(filename, "w") as foz:
for line in fiz_content:
foz.write(line, compress_type=compression)
- # zf.ZipFile.writestr(filename,fiz_content)
- #with zf.ZipFile(filename, "w") as foz:
+ # zf.ZipFile.writestr(filename,fiz_content)
+ # with zf.ZipFile(filename, "w") as foz:
# foz.write(fiz_content)
# sayz(tempfilepath + ' zip amended')
- elif 1: #try:
- found_transp_issue=False
- with gz.open(filename, "rb") as figz:
- with gz.open(tempfilepath, 'wb') as fogz:
- for line in figz:
- if (b'SURFACE_STYLE_TRANSPARENT(1.);' in line):
- #print(line)
- line = re.sub(b'SURFACE_STYLE_TRANSPARENT\(1.\)',b'SURFACE_STYLE_TRANSPARENT(0.)',line)
- found_transp_issue=True
- #print(line)
- fogz.write(line)
+ elif 1: # try:
+ found_transp_issue = False
+ with gz.open(filename, "rb") as figz, gz.open(tempfilepath, "wb") as fogz:
+ for line in figz:
+ if b"SURFACE_STYLE_TRANSPARENT(1.);" in line:
+ # print(line)
+ line = re.sub(rb"SURFACE_STYLE_TRANSPARENT\(1.\)", b"SURFACE_STYLE_TRANSPARENT(0.)", line)
+ found_transp_issue = True
+ # print(line)
+ fogz.write(line)
# sayz(tempfilepath + ' gz amended')
if os.path.exists(filename) and found_transp_issue:
shutil.move(tempfilepath, filename)
- #sayz(filename + ' written')
+ # sayz(filename + ' written')
- else: # except:
+ else: # except:
pass
- elif 'stp' in ext.lower() or 'step' in ext.lower():
- found_transp_issue=False
- filepath = os.path.join(basepath, fname + ext)
+ elif "stp" in ext.lower() or "step" in ext.lower():
+ found_transp_issue = False
+ os.path.join(basepath, fname + ext)
tempdir = tempfile.gettempdir() # get the current temporary directory
tempfilepath = os.path.join(tempdir, fname + ext)
- with open(filename, "rb") as fi:
- with open(tempfilepath, 'wb') as fo:
- for line in fi:
- if (b'SURFACE_STYLE_TRANSPARENT(1.);' in line):
- #print(line)
- line = re.sub(b'SURFACE_STYLE_TRANSPARENT\(1.\)',b'SURFACE_STYLE_TRANSPARENT(0.)',line)
- found_transp_issue=True
- #print(line)
- fo.write(line)
+ with open(filename, "rb") as fi, open(tempfilepath, "wb") as fo:
+ for line in fi:
+ if b"SURFACE_STYLE_TRANSPARENT(1.);" in line:
+ # print(line)
+ line = re.sub(rb"SURFACE_STYLE_TRANSPARENT\(1.\)", b"SURFACE_STYLE_TRANSPARENT(0.)", line)
+ found_transp_issue = True
+ # print(line)
+ fo.write(line)
# sayz(tempfilepath + ' step amended')
if os.path.exists(filename) and found_transp_issue:
shutil.move(tempfilepath, filename)
- #sayz(filename + ' written')
+ # sayz(filename + ' written')
return found_transp_issue
-###
\ No newline at end of file
+
+
+###
diff --git a/test-mb.py b/test-mb.py
index b844963..7a81733 100644
--- a/test-mb.py
+++ b/test-mb.py
@@ -1,6 +1,3 @@
-
-from PySide import QtGui, QtCore
-
# msg_box = QtGui.QMessageBox()
# msg_box.setWindowTitle("Warning")
# msg_box.setText("This will remove ALL Suffix \'.stp\', \'.step\' from selection objects.\nDo you want to continue?")
@@ -9,159 +6,160 @@
# #layout.addWidget(msg_box.txtInp)
# gl = QtGui.QVBoxLayout()
# gl.addWidget(msg_box.txtInp)
-# msg_box.setLayout(gl)
+# msg_box.setLayout(gl)
# msg_box.setInformativeText('Informative text.')
# msg_box.setDetailedText("Detailed text.")
# #msg_box.Text.setTextInteractionFlags (QtCore.Qt.TextEditorInteraction) #(QtCore.Qt.NoTextInteraction) # (QtCore.Qt.TextSelectableByMouse)
# msg_box.setIcon(QtGui.QMessageBox.Critical)
# msg_box.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
# msg_box.setDefaultButton(QtGui.QMessageBox.Cancel)
-#
+#
# ret = msg_box.exec_()
-
-import sys
+from PySide import QtCore
from PySide.QtCore import SIGNAL
-from PySide.QtGui import QDialog, QApplication, QPushButton, QLineEdit, QFormLayout, QLabel, QStyle
+from PySide.QtGui import QDialog, QFormLayout, QLabel, QLineEdit, QPushButton
if 0:
+
class Form(QDialog):
-
def __init__(self, parent=None):
-
- super(Form, self).__init__(parent)
- #self.setWindowIcon(self.style().standardIcon(QStyle.SP_DirIcon))
- #QtGui.QIcon(QtGui.QMessageBox.Critical))
- self.txt = QLabel()
- self.txt.setText("This will remove ALL Suffix from selection objects. .\nDo you want to continue?\n\n\'suffix\'")
+
+ super().__init__(parent)
+ # self.setWindowIcon(self.style().standardIcon(QStyle.SP_DirIcon))
+ # QtGui.QIcon(QtGui.QMessageBox.Critical))
+ self.txt = QLabel()
+ self.txt.setText(
+ "This will remove ALL Suffix from selection objects. .\nDo you want to continue?\n\n'suffix'",
+ )
self.le = QLineEdit()
self.le.setObjectName("suffix_filter")
self.le.setText(".step")
-
+
self.pb = QPushButton()
self.pb.setObjectName("OK")
- self.pb.setText("OK")
-
+ self.pb.setText("OK")
+
self.pbC = QPushButton()
self.pbC.setObjectName("Cancel")
- self.pbC.setText("Cancel")
-
+ self.pbC.setText("Cancel")
+
layout = QFormLayout()
layout.addWidget(self.txt)
layout.addWidget(self.le)
layout.addWidget(self.pb)
layout.addWidget(self.pbC)
-
+
self.setLayout(layout)
- self.connect(self.pb, SIGNAL("clicked()"),self.OK_click)
- self.connect(self.pbC, SIGNAL("clicked()"),self.Cancel_click)
+ self.connect(self.pb, SIGNAL("clicked()"), self.OK_click)
+ self.connect(self.pbC, SIGNAL("clicked()"), self.Cancel_click)
self.setWindowTitle("Warning ...")
-
-
+
def OK_click(self):
# shost is a QString object
filtered = self.le.text()
- print (filtered)
+ print(filtered)
self.close()
+
def Cancel_click(self):
# shost is a QString object
- filtered = '.stp'
- print (filtered)
+ filtered = ".stp"
+ print(filtered)
self.close()
-
-
- #app = QApplication(sys.argv)
+
+ # app = QApplication(sys.argv)
form = Form()
- #form.setIcon(QtGui.QMessageBox.Critical)
+ # form.setIcon(QtGui.QMessageBox.Critical)
form.show()
form.exec_()
- #app.exec_()
+ # app.exec_()
if 1:
- import sys
from PySide.QtCore import *
from PySide.QtGui import *
+
class Widget(QDialog):
-
- def __init__(self, parent= None):
- super(Widget, self).__init__(parent, QtCore.Qt.WindowStaysOnTopHint)
- #QtGui.QMainWindow.__init__(self, None, QtCore.Qt.WindowStaysOnTopHint)
- #icon = style.standardIcon(
+ def __init__(self, parent=None):
+ super().__init__(parent, QtCore.Qt.WindowStaysOnTopHint)
+ # QtGui.QMainWindow.__init__(self, None, QtCore.Qt.WindowStaysOnTopHint)
+ # icon = style.standardIcon(
# QtGui.QStyle.SP_MessageBoxCritical, None, widget)
- #self.setWindowIcon(self.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical))
- #self.setIcon(self.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical))
- #self.setIcon(self.style().standardIcon(QStyle.SP_DirIcon))
- #QtGui.QIcon(QtGui.QMessageBox.Critical))
- #icon = QtGui.QIcon()
- #icon.addPixmap(QtGui.QPixmap("icons/157-stats-bars.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
- #Widget.setWindowIcon(icon)
-
- self.txt = QLabel()
- self.txt.setText("This will remove ALL Suffix from selection objects. \nDo you want to continue?\n\n\'suffix\'")
+ # self.setWindowIcon(self.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical))
+ # self.setIcon(self.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical))
+ # self.setIcon(self.style().standardIcon(QStyle.SP_DirIcon))
+ # QtGui.QIcon(QtGui.QMessageBox.Critical))
+ # icon = QtGui.QIcon()
+ # icon.addPixmap(QtGui.QPixmap("icons/157-stats-bars.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
+ # Widget.setWindowIcon(icon)
+
+ self.txt = QLabel()
+ self.txt.setText(
+ "This will remove ALL Suffix from selection objects. \nDo you want to continue?\n\n'suffix'",
+ )
self.le = QLineEdit()
self.le.setObjectName("suffix_filter")
self.le.setText(".step")
-
+
self.pb = QPushButton()
self.pb.setObjectName("OK")
- self.pb.setText("OK")
-
+ self.pb.setText("OK")
+
self.pbC = QPushButton()
self.pbC.setObjectName("Cancel")
- self.pbC.setText("Cancel")
-
+ self.pbC.setText("Cancel")
+
layout = QVBoxLayout()
layout.addWidget(self.txt)
layout.addWidget(self.le)
layout.addWidget(self.pb)
layout.addWidget(self.pbC)
-
+
self.setWindowTitle("Warning ...")
- #self.setWindowIcon(self.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical))
-
+ # self.setWindowIcon(self.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical))
+
# btn_folder = QPushButton("Folder")
# btn_folder.setIcon(self.style().standardIcon(QStyle.SP_DirIcon))
- #
+ #
# btn_one = QPushButton("Play")
# btn_one.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))
- #
+ #
# btn_two = QPushButton("Stop")
# btn_two.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))
- #
+ #
# btn_three = QPushButton("Pause")
# btn_three.setIcon(self.style().standardIcon(QStyle.SP_MediaPause))
-
- #layout = QHBoxLayout()
- #layout.addWidget(btn_folder)
- #layout.addWidget(btn_one)
- #layout.addWidget(btn_two)
- #layout.addWidget(btn_three)
-
+
+ # layout = QHBoxLayout()
+ # layout.addWidget(btn_folder)
+ # layout.addWidget(btn_one)
+ # layout.addWidget(btn_two)
+ # layout.addWidget(btn_three)
+
self.setLayout(layout)
- #self.setLayout(layout)
- self.connect(self.pb, SIGNAL("clicked()"),self.OK_click)
- self.connect(self.pbC, SIGNAL("clicked()"),self.Cancel_click)
-
+ # self.setLayout(layout)
+ self.connect(self.pb, SIGNAL("clicked()"), self.OK_click)
+ self.connect(self.pbC, SIGNAL("clicked()"), self.Cancel_click)
+
def OK_click(self):
# shost is a QString object
filtered = self.le.text()
- print (filtered)
+ print(filtered)
self.close()
+
def Cancel_click(self):
# shost is a QString object
- filtered = '.stp'
- print (filtered)
+ filtered = ".stp"
+ print(filtered)
self.close()
-
-
- #mw = FreeCADGui.getMainWindow()
- #dialog = Widget(mw)
+
+ # mw = FreeCADGui.getMainWindow()
+ # dialog = Widget(mw)
dialog = Widget()
- #dialog.setWindowIcon(dialog.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical)) #non py3 ok
-
- #my_dialog = QDialog(self)
- #my_dialog.exec_()
+ # dialog.setWindowIcon(dialog.style().standardIcon(QtGui.QStyle.SP_MessageBoxCritical)) #non py3 ok
+
+ # my_dialog = QDialog(self)
+ # my_dialog.exec_()
dialog.show()
- #dialog.setModal(True)
- #dialog.exec_()
\ No newline at end of file
+ # dialog.setModal(True)
+ # dialog.exec_()
diff --git a/tracks.py b/tracks.py
index c28f218..e0c080f 100644
--- a/tracks.py
+++ b/tracks.py
@@ -1,84 +1,98 @@
#!/usr/bin/python
-# -*- coding: utf-8 -*-
-#****************************************************************************
+# ****************************************************************************
global tracks_version
-tracks_version = '2.7.0'
+tracks_version = "2.7.0"
-import kicad_parser
-#import kicad_parser; import importlib; importlib.reload(kicad_parser)
+# import kicad_parser; import importlib; importlib.reload(kicad_parser)
import time
+
import PySide
-from PySide import QtGui, QtCore
+from PySide import QtCore, QtGui
+
+import kicad_parser
+
QtWidgets = QtGui
-import sys,os
-import FreeCAD, FreeCADGui
-import Draft, Part
+import os
+
+import Draft
+import FreeCAD
+import FreeCADGui
+import Part
+
global start_time, last_pcb_path, min_drill_size
global FC_export_min_version
-FC_export_min_version="11670" #11670 latest JM
+FC_export_min_version = "11670" # 11670 latest JM
# from kicadStepUptools import PLine
-from kicad_parser import makeVect, make_gr_rect, make_gr_poly, makeThickLine
-from fcad_parser import unquote #maui
+from fcad_parser import unquote # maui
+from kicad_parser import make_gr_poly, make_gr_rect, makeThickLine, makeVect
global use_AppPart, use_Links, use_LinkGroups
-use_AppPart=False # False
-use_Links=False
+use_AppPart = False # False
+use_Links = False
use_LinkGroups = False
-if 'LinkView' in dir(FreeCADGui):
+if "LinkView" in dir(FreeCADGui):
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- if prefs.GetBool('asm3_linkGroups'):
+ if prefs.GetBool("asm3_linkGroups"):
use_LinkGroups = True
- use_Links=True #False
- #print('using \'LinkGroups\' and \'Links\'')
- elif prefs.GetBool('asm3_links'):
- use_Links=True #False
- #print('using \'Part\' container and \'Links\'')
+ use_Links = True # False
+ # print('using \'LinkGroups\' and \'Links\'')
+ elif prefs.GetBool("asm3_links"):
+ use_Links = True # False
+ # print('using \'Part\' container and \'Links\'')
else:
use_LinkGroups = False
- #print('using \'Part\' container')
+ # print('using \'Part\' container')
else:
use_LinkGroups = False
- #print('using \'Part\' container')
-#
+ # print('using \'Part\' container')
+
+
def getFCversion():
- FC_majorV=int(float(FreeCAD.Version()[0]))
- FC_minorV=int(float(FreeCAD.Version()[1]))
+ FC_majorV = int(float(FreeCAD.Version()[0]))
+ FC_minorV = int(float(FreeCAD.Version()[1]))
try:
- FC_git_Nbr=int (float(FreeCAD.Version()[2].strip(" (Git)").split(' ')[0])) #+int(FreeCAD.Version()[2].strip(" (Git)").split(' ')[1])
+ FC_git_Nbr = int(
+ float(FreeCAD.Version()[2].strip(" (Git)").split(" ")[0]),
+ ) # +int(FreeCAD.Version()[2].strip(" (Git)").split(' ')[1])
except:
- FC_git_Nbr=0
- return FC_majorV,FC_minorV,FC_git_Nbr
-
-FC_majorV,FC_minorV,FC_git_Nbr=getFCversion()
-FreeCAD.Console.PrintWarning('FC Version '+str(FC_majorV)+str(FC_minorV)+"-"+str(FC_git_Nbr)+'\n')
-if FC_majorV == 0 and FC_minorV == 17:
- if FC_git_Nbr >= int(FC_export_min_version):
- use_AppPart=True
-#if FreeCAD.Version()[2] == 'Unknown': #workaround for local building
+ FC_git_Nbr = 0
+ return FC_majorV, FC_minorV, FC_git_Nbr
+
+
+FC_majorV, FC_minorV, FC_git_Nbr = getFCversion()
+FreeCAD.Console.PrintWarning("FC Version " + str(FC_majorV) + str(FC_minorV) + "-" + str(FC_git_Nbr) + "\n")
+if FC_majorV == 0 and FC_minorV == 17 and FC_git_Nbr >= int(FC_export_min_version):
+ use_AppPart = True
+# if FreeCAD.Version()[2] == 'Unknown': #workaround for local building
# use_AppPart=True
if FC_majorV > 0:
- use_AppPart=True
+ use_AppPart = True
if FC_majorV == 0 and FC_minorV > 17:
- #if FC_git_Nbr >= int(FC_export_min_version):
- use_AppPart=True
+ # if FC_git_Nbr >= int(FC_export_min_version):
+ use_AppPart = True
+
+
+def current_milli_time():
+ return round(time.time() * 1000)
-current_milli_time = lambda: int(round(time.time() * 1000))
def say_time():
end_milli_time = current_milli_time()
- running_time=(end_milli_time-start_time)/1000
- msg="running time: "+str(running_time)+"sec"
+ running_time = (end_milli_time - start_time) / 1000
+ msg = "running time: " + str(running_time) + "sec"
print(msg)
+
+
###
-#try: #maui
+# try: #maui
# basestring
-#except NameError:
+# except NameError:
# basestring = str
-py2=False
+py2 = False
try: ## maui py3
unicode = unicode
except NameError:
@@ -86,88 +100,91 @@ def say_time():
str = str
unicode = str
bytes = bytes
- basestring = (str,bytes)
+ basestring = (str, bytes)
else:
# 'unicode' exists, must be Python 2
str = str
unicode = unicode
bytes = str
basestring = basestring
- py2=True
+ py2 = True
+
def reload_lib(lib):
- if (sys.version_info > (3, 0)):
- import importlib
- importlib.reload(lib)
- else:
- reload (lib)
+ import importlib
+
+ importlib.reload(lib)
+
def recompute_active_object():
try:
FreeCAD.ActiveDocument.ActiveObject.recompute(True)
except:
FreeCAD.ActiveDocument.ActiveObject.recompute()
-##
+
+
+##
+
def crc_gen_t(data):
import binascii
import re
-
- #data=u'Würfel'
- content=re.sub(r'[^\x00-\x7F]+','_', data)
- #make_unicode(hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
- #hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:].encode('utf-8')
- #print(data +u'_'+ hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
- return u'_'+ make_unicode_t(hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
+
+ # data=u'Würfel'
+ content = re.sub(r"[^\x00-\x7F]+", "_", data)
+ # make_unicode(hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
+ # hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:].encode('utf-8')
+ # print(data +u'_'+ hex(binascii.crc_hqx(content.encode('utf-8'), 0x0000))[2:])
+ return "_" + make_unicode_t(hex(binascii.crc_hqx(content.encode("utf-8"), 0x0000))[2:])
+
+
##
+
def make_unicode_t(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.decode('utf-8')
- return input
- else: #py2
- if type(input) != unicode:
- input = input.decode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.decode("utf-8")
+ if type(input) != unicode:
+ return input.decode("utf-8")
+ return input
+
def mkColor(*color):
- if len(color)==1:
- if isinstance(color[0],basestring):
- if color[0].startswith('#'):
- #color = color[0].replace('#','0x')
- #color = int(color,0)
- #print (color)
- #r = float((color>>24)&0xFF)
- #g = float((color>>16)&0xFF)
- #b = float((color>>8)&0xFF)
- color = color[0] #[1:]
- #print(color[1:3])
- r = int((color[1:3]), 16) #/255
- g = int((color[3:5]), 16) #/255
- b = int((color[5:7]), 16) #/255
- #print(r,g,b);stop
- #print(r,g,b)
- #stop
+ if len(color) == 1:
+ if isinstance(color[0], basestring):
+ if color[0].startswith("#"):
+ # color = color[0].replace('#','0x')
+ # color = int(color,0)
+ # print (color)
+ # r = float((color>>24)&0xFF)
+ # g = float((color>>16)&0xFF)
+ # b = float((color>>8)&0xFF)
+ color = color[0] # [1:]
+ # print(color[1:3])
+ r = int((color[1:3]), 16) # /255
+ g = int((color[3:5]), 16) # /255
+ b = int((color[5:7]), 16) # /255
+ # print(r,g,b);stop
+ # print(r,g,b)
+ # stop
else:
- color = int(color[0],0)
- r = float((color>>24)&0xFF)
- g = float((color>>16)&0xFF)
- b = float((color>>8)&0xFF)
+ color = int(color[0], 0)
+ r = float((color >> 24) & 0xFF)
+ g = float((color >> 16) & 0xFF)
+ b = float((color >> 8) & 0xFF)
else:
color = color[0]
- r = float((color>>24)&0xFF)
- g = float((color>>16)&0xFF)
- b = float((color>>8)&0xFF)
+ r = float((color >> 24) & 0xFF)
+ g = float((color >> 16) & 0xFF)
+ b = float((color >> 8) & 0xFF)
else:
- r,g,b = color
- return (r/255.0,g/255.0,b/255.0)
+ r, g, b = color
+ return (r / 255.0, g / 255.0, b / 255.0)
+
+
##
-#colors = {
+# colors = {
# 'board':makeColor("0x3A6629"),
# 'pad':{0:makeColor(219,188,126)},
# 'zone':{0:makeColor(200,117,51)},
@@ -175,49 +192,49 @@ def mkColor(*color):
# 'copper':{0:makeColor(200,117,51)},
# }
-def extrude_holes (holes,w):
- FreeCAD.ActiveDocument.addObject("Part::Extrusion","Extrude_drills")
- extrude_d_name=FreeCAD.ActiveDocument.ActiveObject.Name
+def extrude_holes(holes, w):
+
+ FreeCAD.ActiveDocument.addObject("Part::Extrusion", "Extrude_drills")
+ extrude_d_name = FreeCAD.ActiveDocument.ActiveObject.Name
FreeCAD.ActiveDocument.getObject(extrude_d_name).Base = FreeCAD.ActiveDocument.getObject(holes.Name)
- FreeCAD.ActiveDocument.getObject(extrude_d_name).Dir = (0,0,w)
- FreeCAD.ActiveDocument.getObject(extrude_d_name).Solid = (True)
- FreeCAD.ActiveDocument.getObject(extrude_d_name).TaperAngle = (0)
+ FreeCAD.ActiveDocument.getObject(extrude_d_name).Dir = (0, 0, w)
+ FreeCAD.ActiveDocument.getObject(extrude_d_name).Solid = True
+ FreeCAD.ActiveDocument.getObject(extrude_d_name).TaperAngle = 0
FreeCAD.ActiveDocument.getObject(extrude_d_name).Symmetric = True
FreeCADGui.ActiveDocument.getObject(holes.Name).Visibility = False
- FreeCAD.ActiveDocument.getObject(extrude_d_name).Label = 'solid_drills'
- extrude_drill_name=FreeCAD.ActiveDocument.ActiveObject.Name
+ FreeCAD.ActiveDocument.getObject(extrude_d_name).Label = "solid_drills"
recompute_active_object()
FreeCADGui.ActiveDocument.getObject(holes.Name).Visibility = False
-#
-def cut_fuzzy(base,tool,ftol):
+
+def cut_fuzzy(base, tool, ftol):
Part.show(base.Shape.cut(tool.Shape, ftol))
-
-#
-def cut_out_tracks (pcbsk,tracks,tname_sfx):
-
+
+def cut_out_tracks(pcbsk, tracks, tname_sfx):
+
# import tracks; import importlib;importlib.reload(tracks)
import random
+
temp_tobedeleted = []
removing_temp_objs = False
- Extrude_Name = 'Extrude' + str(random.randrange(1,100))
- FreeCAD.ActiveDocument.addObject('Part::Extrusion', Extrude_Name)
+ Extrude_Name = "Extrude" + str(random.randrange(1, 100))
+ FreeCAD.ActiveDocument.addObject("Part::Extrusion", Extrude_Name)
extrude = FreeCAD.ActiveDocument.ActiveObject
- #f = FreeCAD.ActiveDocument.getObject('Extrude')
+ # f = FreeCAD.ActiveDocument.getObject('Extrude')
# print (pcbsk.Name)
- #shp = pcbsk.Shape.copy()
+ # shp = pcbsk.Shape.copy()
# shp_nw = pcbsk.copy()
- #Part.show(shp)
+ # Part.show(shp)
doc = FreeCAD.ActiveDocument
FreeCADGui.Selection.clearSelection()
- FreeCADGui.Selection.addSelection(doc.Name,pcbsk.Name)
- FreeCADGui.runCommand('Std_Copy',0)
- FreeCADGui.runCommand('Std_Paste',0)
- shp_nw=FreeCAD.ActiveDocument.ActiveObject
- extrude.Base = shp_nw #pcbsk
+ FreeCADGui.Selection.addSelection(doc.Name, pcbsk.Name)
+ FreeCADGui.runCommand("Std_Copy", 0)
+ FreeCADGui.runCommand("Std_Paste", 0)
+ shp_nw = FreeCAD.ActiveDocument.ActiveObject
+ extrude.Base = shp_nw # pcbsk
extrude.DirMode = "Custom"
extrude.Dir = (0.000, 0.000, 1.000)
extrude.DirLink = None
@@ -228,37 +245,56 @@ def cut_out_tracks (pcbsk,tracks,tname_sfx):
extrude.Symmetric = True
extrude.TaperAngle = 0.000000000000000
extrude.TaperAngleRev = 0.000000000000000
- extrude.ViewObject.ShapeColor=getattr(pcbsk.getLinkedObject(True).ViewObject,'ShapeColor',extrude.ViewObject.ShapeColor)
- extrude.ViewObject.LineColor=getattr(pcbsk.getLinkedObject(True).ViewObject,'LineColor',extrude.ViewObject.LineColor)
- extrude.ViewObject.PointColor=getattr(pcbsk.getLinkedObject(True).ViewObject,'PointColor',extrude.ViewObject.PointColor)
+ extrude.ViewObject.ShapeColor = getattr(
+ pcbsk.getLinkedObject(True).ViewObject,
+ "ShapeColor",
+ extrude.ViewObject.ShapeColor,
+ )
+ extrude.ViewObject.LineColor = getattr(
+ pcbsk.getLinkedObject(True).ViewObject,
+ "LineColor",
+ extrude.ViewObject.LineColor,
+ )
+ extrude.ViewObject.PointColor = getattr(
+ pcbsk.getLinkedObject(True).ViewObject,
+ "PointColor",
+ extrude.ViewObject.PointColor,
+ )
pcbsk.Visibility = False
FreeCAD.ActiveDocument.recompute()
- Common_Top_Name = "Common_Top"+ str(random.randrange(1,100))
- FreeCAD.ActiveDocument.addObject("Part::MultiCommon",Common_Top_Name)
+ Common_Top_Name = "Common_Top" + str(random.randrange(1, 100))
+ FreeCAD.ActiveDocument.addObject("Part::MultiCommon", Common_Top_Name)
Common_Top = FreeCAD.ActiveDocument.ActiveObject
- Common_Top.Shapes = [tracks,extrude,]
- FreeCADGui.ActiveDocument.getObject(tracks.Name).Visibility=False
- FreeCADGui.ActiveDocument.getObject(extrude.Name).Visibility=False
+ Common_Top.Shapes = [
+ tracks,
+ extrude,
+ ]
+ FreeCADGui.ActiveDocument.getObject(tracks.Name).Visibility = False
+ FreeCADGui.ActiveDocument.getObject(extrude.Name).Visibility = False
FreeCAD.ActiveDocument.recompute()
-
+
# placing inside the container
try:
- extrude.adjustRelativeLinks(FreeCAD.ActiveDocument.getObject('Board_Geoms'+tname_sfx))
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+tname_sfx).addObject(extrude)
+ extrude.adjustRelativeLinks(FreeCAD.ActiveDocument.getObject("Board_Geoms" + tname_sfx))
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + tname_sfx).addObject(extrude)
except:
- FreeCAD.Console.PrintWarning('error on moving Board Geoms inside Part container\n')
+ FreeCAD.Console.PrintWarning("error on moving Board Geoms inside Part container\n")
# simple copy
- FreeCAD.ActiveDocument.addObject('Part::Feature',tracks.Label+'_').Shape=FreeCAD.ActiveDocument.getObject(Common_Top.Name).Shape
- tracks_ct = FreeCAD.ActiveDocument.ActiveObject
- tracks_ctV = FreeCADGui.ActiveDocument.ActiveObject
- new_label=tracks.Label +'_cut'
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(Common_Top.Name).ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.ShapeColor=FreeCADGui.ActiveDocument.getObject(Common_Top.Name).ShapeColor
- FreeCADGui.ActiveDocument.ActiveObject.LineColor=FreeCADGui.ActiveDocument.getObject(Common_Top.Name).LineColor
- FreeCADGui.ActiveDocument.ActiveObject.PointColor=FreeCADGui.ActiveDocument.getObject(Common_Top.Name).PointColor
- FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor=FreeCADGui.ActiveDocument.getObject(Common_Top.Name).DiffuseColor
- FreeCADGui.ActiveDocument.ActiveObject.Transparency=FreeCADGui.ActiveDocument.getObject(Common_Top.Name).Transparency
- FreeCAD.ActiveDocument.ActiveObject.Label=new_label
+ FreeCAD.ActiveDocument.addObject("Part::Feature", tracks.Label + "_").Shape = FreeCAD.ActiveDocument.getObject(
+ Common_Top.Name,
+ ).Shape
+ new_label = tracks.Label + "_cut"
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(Common_Top.Name).ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(Common_Top.Name).ShapeColor
+ FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject(Common_Top.Name).LineColor
+ FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject(Common_Top.Name).PointColor
+ FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject(
+ Common_Top.Name,
+ ).DiffuseColor
+ FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject(
+ Common_Top.Name,
+ ).Transparency
+ FreeCAD.ActiveDocument.ActiveObject.Label = new_label
tracks_ct_Name = FreeCAD.ActiveDocument.ActiveObject.Name
if removing_temp_objs:
FreeCAD.ActiveDocument.removeObject(Common_Top.Name)
@@ -267,637 +303,695 @@ def cut_out_tracks (pcbsk,tracks,tname_sfx):
FreeCAD.ActiveDocument.removeObject(shp_nw.Name)
else:
doc = FreeCAD.ActiveDocument
- #temp_tobedeleted.append([doc.getObject(Common_Top.Name),doc.getObject(tracks.Name),doc.getObject(extrude.Name)])
+ # temp_tobedeleted.append([doc.getObject(Common_Top.Name),doc.getObject(tracks.Name),doc.getObject(extrude.Name)])
temp_tobedeleted.append(doc.getObject(Common_Top.Name))
temp_tobedeleted.append(doc.getObject(tracks.Name))
temp_tobedeleted.append(doc.getObject(extrude.Name))
temp_tobedeleted.append(doc.getObject(shp_nw.Name))
FreeCAD.ActiveDocument.getObject(tracks_ct_Name).Label = new_label
FreeCAD.ActiveDocument.recompute()
-
+
return tracks_ct_Name, temp_tobedeleted
+
+
##
-def simple_cpy (obj,lbl):
- copy = FreeCAD.ActiveDocument.addObject('Part::Feature',obj.Name)
+def simple_cpy(obj, lbl):
+ copy = FreeCAD.ActiveDocument.addObject("Part::Feature", obj.Name)
copy.Label = lbl
copy.Shape = obj.Shape
- copy.ViewObject.ShapeColor = obj.ViewObject.ShapeColor
- copy.ViewObject.LineColor = obj.ViewObject.LineColor
- copy.ViewObject.PointColor = obj.ViewObject.PointColor
+ copy.ViewObject.ShapeColor = obj.ViewObject.ShapeColor
+ copy.ViewObject.LineColor = obj.ViewObject.LineColor
+ copy.ViewObject.PointColor = obj.ViewObject.PointColor
copy.ViewObject.DiffuseColor = obj.ViewObject.DiffuseColor
return copy
+
+
#
-#def rmv_obj(o):
+# def rmv_obj(o):
# FreeCADGui.Selection.clearSelection()
# FreeCADGui.Selection.addSelection(doc.getObject(pads.Name))
# removesubtree(FreeCADGui.Selection.getSelection())
#
-from kicadStepUptools import removesubtree, cfg_read_all
-from kicadStepUptools import make_unicode, make_string
-import fcad_parser
-from fcad_parser import KicadPCB,SexpList
+from fcad_parser import KicadPCB
+from kicadStepUptools import make_string, make_unicode
+
-#filename="C:/Cad/Progetti_K/ksu-test/pic_smart_switch.kicad_pcb"
-#filename="C:/Cad/Progetti_K/eth-32gpio/eth-32gpio.kicad_pcb"
-def addtracks(fname = None):
+# filename="C:/Cad/Progetti_K/ksu-test/pic_smart_switch.kicad_pcb"
+# filename="C:/Cad/Progetti_K/eth-32gpio/eth-32gpio.kicad_pcb"
+def addtracks(fname=None):
global start_time, last_pcb_path, min_drill_size
global use_LinkGroups, use_AppPart, tracks_version
- import sys
- import kicad_parser
- FreeCAD.Console.PrintMessage('kicad_parser_version '+kicad_parser.__kicad_parser_version__+'\n') # maui
+ FreeCAD.Console.PrintMessage("kicad_parser_version " + kicad_parser.__kicad_parser_version__ + "\n") # noqa: F823 # maui
# cfg_read_all() it doesn't work through different files
# print (min_drill_size)
-
- FreeCAD.Console.PrintMessage('tracks version: '+tracks_version+'\n')
- Filter=""
+
+ FreeCAD.Console.PrintMessage("tracks version: " + tracks_version + "\n")
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
if fname is None:
last_pcb_path = pg.GetString("last_pcb_path")
- if len (last_pcb_path) == 0:
- last_pcb_path = ""
+ if len(last_pcb_path) == 0:
+ last_pcb_path = ""
prefs_ = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- #print('native_dlg',prefs_.GetBool('native_dlg'))
- if not(prefs_.GetBool('not_native_dlg')):
- fname, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open File...",
- make_unicode(last_pcb_path), "*.kicad_pcb")
+ # print('native_dlg',prefs_.GetBool('native_dlg'))
+ if not (prefs_.GetBool("not_native_dlg")):
+ fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open File...",
+ make_unicode(last_pcb_path),
+ "*.kicad_pcb",
+ )
else:
- fname, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open File...",
- make_unicode(last_pcb_path), "*.kicad_pcb",options=QtWidgets.QFileDialog.DontUseNativeDialog)
- path, name = os.path.split(fname)
- #filename=os.path.splitext(name)[0]
+ fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName(
+ None,
+ "Open File...",
+ make_unicode(last_pcb_path),
+ "*.kicad_pcb",
+ options=QtWidgets.QFileDialog.DontUseNativeDialog,
+ )
+ _path, _name = os.path.split(fname)
+ # filename=os.path.splitext(name)[0]
filename = fname
- #importDXF.open(os.path.join(dirname,filename))
+ # importDXF.open(os.path.join(dirname,filename))
if len(fname) > 0:
- start_time=current_milli_time()
- last_pcb_path=os.path.dirname(fname)
- path, ftname = os.path.split(fname)
- ftname=os.path.splitext(ftname)[0]
- ftname_sfx=crc_gen_t(make_unicode_t(ftname))
+ start_time = current_milli_time()
+ last_pcb_path = os.path.dirname(fname)
+ _path, ftname = os.path.split(fname)
+ ftname = os.path.splitext(ftname)[0]
+ ftname_sfx = crc_gen_t(make_unicode_t(ftname))
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
- pg.SetString("last_pcb_path", make_string(last_pcb_path)) # py3 .decode("utf-8")
+ pg.SetString("last_pcb_path", make_string(last_pcb_path)) # py3 .decode("utf-8")
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
- skip_import_zones = prefs.GetBool('skip_import_zones')
- skip_import_pads = prefs.GetBool('skip_import_pads')
- skip_import_tracks = prefs.GetBool('skip_import_tracks')
- pcb_color_pos = prefs.GetInt('pcb_color')
- #pcb_color_values = [light_green,green,blue,red,purple,darkgreen,darkblue,lightblue,yellow,black,white]
- assign_col=['#41c382','#5d917a','#2474cf','#ff4000','#9a1a85','#3c7f5d','#426091','#005fff','#fff956','#4d4d4d','#f0f0f0']
- #print(pcb_color_pos)
- trk_col = (assign_col[pcb_color_pos])
- if pcb_color_pos == 9:
- slk_col = '#2d2d2d'
- else:
- slk_col = '#f8f8f0'
+ skip_import_zones = prefs.GetBool("skip_import_zones")
+ skip_import_pads = prefs.GetBool("skip_import_pads")
+ skip_import_tracks = prefs.GetBool("skip_import_tracks")
+ pcb_color_pos = prefs.GetInt("pcb_color")
+ # pcb_color_values = [light_green,green,blue,red,purple,darkgreen,darkblue,lightblue,yellow,black,white]
+ assign_col = [
+ "#41c382",
+ "#5d917a",
+ "#2474cf",
+ "#ff4000",
+ "#9a1a85",
+ "#3c7f5d",
+ "#426091",
+ "#005fff",
+ "#fff956",
+ "#4d4d4d",
+ "#f0f0f0",
+ ]
+ # print(pcb_color_pos)
+ trk_col = assign_col[pcb_color_pos]
# mypcb = KicadPCB.load(filename)
# pcbThickness = float(mypcb.general.thickness)
- #print (mypcb.general.thickness)
- #print(mypcb.layers)
+ # print (mypcb.general.thickness)
+ # print(mypcb.layers)
pcb_sk = None
- #if version>=4:
- Top_lvl=0;Bot_lvl=31
- #for lynbr in mypcb.layers: #getting layers name
+ # if version>=4:
+ Top_lvl = 0
+ Bot_lvl = 31
+ # for lynbr in mypcb.layers: #getting layers name
# if float(lynbr) == Top_lvl:
# LvlTopName=(mypcb.layers['{0}'.format(str(lynbr))][0])
# if float(lynbr) == Bot_lvl:
# LvlBotName=(mypcb.layers['{0}'.format(str(lynbr))][0])
- #print(LvlTopName,' ',LvlBotName)
- import kicad_parser
+ # print(LvlTopName,' ',LvlBotName)
+ import kicad_parser
+
# reload_lib(kicad_parser)
- #pcb = kicad_parser.KicadFcad(filename,via_skip_hole=False,via_bound=0)
- pcb = kicad_parser.KicadFcad(filename,merge_pads=False, via_bound=(-1 if skip_import_tracks else 0)) # creating multiple shape, one each pad item
+ # pcb = kicad_parser.KicadFcad(filename,via_skip_hole=False,via_bound=0)
+ pcb = kicad_parser.KicadFcad(
+ filename,
+ merge_pads=False,
+ via_bound=(-1 if skip_import_tracks else 0),
+ ) # creating multiple shape, one each pad item
# pcb = kicad_parser.KicadFcad(filename,merge_pads=True)
- #kicad.KicadFcad(filename,via_skip_hole=False,via_bound=1)
- ## pcb = kicad_parser.KicadFcad(filename, arc_fit_accuracy=1e-4) #to increase accuracy
+ # kicad.KicadFcad(filename,via_skip_hole=False,via_bound=1)
+ ## pcb = kicad_parser.KicadFcad(filename, arc_fit_accuracy=1e-4) #to increase accuracy
# pcbThickness = pcb.board_thickness ## this doesn't always give the full board thickness
# print(pcbThickness,'pcbThickness')
-
+
mypcb = KicadPCB.load(filename)
pcbThickness = float(mypcb.general.thickness)
# print(pcbThickness,'mypcb.pcbThickness')
- #pcbThickness = float(pcb.general.thickness)
- #pcb.setLayer(LvlTopName)
- for lynbr in mypcb.layers: #getting layers name
- #print('layer',lynbr)
- #print(mypcb.layers[lynbr])
- if 'F.Cu' in str(mypcb.layers[lynbr]):
- Top_lvl=int(lynbr)
- if 'B.Cu' in str(mypcb.layers[lynbr]):
- Bot_lvl=int(lynbr)
- for lynbr in mypcb.layers: #getting layers name
- #print(mypcb.layers[lynbr],'layer',lynbr)
- if int(lynbr)==Top_lvl:
- FreeCAD.Console.PrintMessage('Top_name='+str(mypcb.layers[lynbr][0])+'\n')
- #print('Top_name=',mypcb.layers[lynbr][0])
- if len(mypcb.layers[lynbr])>2:
- FreeCAD.Console.PrintMessage('AliasTop_name='+str(mypcb.layers[lynbr][2])+'\n')
- if int(lynbr)==Bot_lvl:
- FreeCAD.Console.PrintMessage('Bot_nam='+str(mypcb.layers[lynbr][0])+'\n')
- if len(mypcb.layers[lynbr])>2:
- FreeCAD.Console.PrintMessage('AliasBot_name='+str(mypcb.layers[lynbr][2])+'\n')
- FreeCAD.Console.PrintMessage('Top_lvl='+str(Top_lvl)+'; Bot_lvl='+str(Bot_lvl)+'\n')
- #stop
-
- minSizeDrill = 0.0 #0.8
- #print(pcb.colors)
+ # pcbThickness = float(pcb.general.thickness)
+ # pcb.setLayer(LvlTopName)
+ for lynbr in mypcb.layers: # getting layers name
+ # print('layer',lynbr)
+ # print(mypcb.layers[lynbr])
+ if "F.Cu" in str(mypcb.layers[lynbr]):
+ Top_lvl = int(lynbr)
+ if "B.Cu" in str(mypcb.layers[lynbr]):
+ Bot_lvl = int(lynbr)
+ for lynbr in mypcb.layers: # getting layers name
+ # print(mypcb.layers[lynbr],'layer',lynbr)
+ if int(lynbr) == Top_lvl:
+ FreeCAD.Console.PrintMessage("Top_name=" + str(mypcb.layers[lynbr][0]) + "\n")
+ # print('Top_name=',mypcb.layers[lynbr][0])
+ if len(mypcb.layers[lynbr]) > 2:
+ FreeCAD.Console.PrintMessage("AliasTop_name=" + str(mypcb.layers[lynbr][2]) + "\n")
+ if int(lynbr) == Bot_lvl:
+ FreeCAD.Console.PrintMessage("Bot_nam=" + str(mypcb.layers[lynbr][0]) + "\n")
+ if len(mypcb.layers[lynbr]) > 2:
+ FreeCAD.Console.PrintMessage("AliasBot_name=" + str(mypcb.layers[lynbr][2]) + "\n")
+ FreeCAD.Console.PrintMessage("Top_lvl=" + str(Top_lvl) + "; Bot_lvl=" + str(Bot_lvl) + "\n")
+ # stop
+
+ # print(pcb.colors)
# https://www.seeedstudio.com/blog/2017/07/23/why-are-printed-circuit-boards-are-usually-green-in-colour/
- # deep-sea blue, Ferrari red, sunshine yellow, slick black, pure white and of course good ol’ green
+ # deep-sea blue, Ferrari red, sunshine yellow, slick black, pure white and of course good ol' green
# (r/255.0,g/255.0,b/255.0)
pcb_col = pcb.colors
- #zone_col = pcb_col['zone'][0]
- #track_col = pcb_col['track'][0]
- pcb_col['track'][0] = mkColor(trk_col)
- pcb_col['zone'][0] = mkColor(trk_col)
+ # zone_col = pcb_col['zone'][0]
+ # track_col = pcb_col['track'][0]
+ pcb_col["track"][0] = mkColor(trk_col)
+ pcb_col["zone"][0] = mkColor(trk_col)
# print(pcb_col['track'][0])
# print(pcb_col['pad'][0])
# print(pcb_col)
- #pcb_col['track'][0] = mkColor('#147b9d')
- #pcb_col['zone'][0] = mkColor('#147b9d')
- #pcb.colors = {
+ # pcb_col['track'][0] = mkColor('#147b9d')
+ # pcb_col['zone'][0] = mkColor('#147b9d')
+ # pcb.colors = {
# 'board':mkColor("0x3A6629"),
# 'pad':{0:mkColor(219,188,126)},
# 'zone':{0:mkColor('#147b9d')},
# 'track':{0:mkColor(26,157,204)},
# 'copper':{0:mkColor(200,117,51)},
- #}
- #pcb.colors={'board':(1.,1.,1.),'pad':{0:(219/255,188/255,126/255)},'zone':{0:(0.,1.,0.)},'track':{0:(0.,1.,1.)},'copper':{0:(0.,1.,1.)},}
+ # }
+ # pcb.colors={'board':(1.,1.,1.),'pad':{0:(219/255,188/255,126/255)},'zone':{0:(0.,1.,0.)},'track':{0:(0.,1.,1.)},'copper':{0:(0.,1.,1.)},}
pcb.setLayer(Top_lvl)
- #try: #doing top tracks layer
+ # try: #doing top tracks layer
## pcb.makeCopper(holes=True, minSize=minSizeDrill)
- # pcb.make(copper_thickness=0.035, board_thickness=pcbThickness, combo=False, fuseCoppers=True )
+ # pcb.make(copper_thickness=0.035, board_thickness=pcbThickness, combo=False, fuseCoppers=True )
# pcb.makeCopper(holes=True,fuse=False)
# say_time()
# stop
topPads = None
topTracks = None
topZones = None
- deltaz = 0.01 #10 micron
+ deltaz = 0.01 # 10 micron
add_toberemoved = []
- if FreeCAD.ActiveDocument is not None:
- objsNum = len(FreeCAD.ActiveDocument.Objects)
- else:
- objsNum = 0
- #pcb.makePads(shape_type='face',thickness=0.05,holes=True,fit_arcs=True) #,prefix='')
- if skip_import_pads != True:
- pcb.makePads(shape_type='face',thickness=0.05,holes=True,fit_arcs=True) #,prefix='')
- if FreeCAD.ActiveDocument is not None:
- if objsNum < len(FreeCAD.ActiveDocument.Objects):
- pads=FreeCAD.ActiveDocument.ActiveObject
- pads.Placement.Base.z = pads.Placement.Base.z + 2*deltaz
- new_obj = simple_cpy(pads,'topPads'+ftname_sfx)
- say_time()
- # removesubtree([pads])
- pads.ViewObject.Visibility = False
- add_toberemoved.append([pads])
- topPads = new_obj
+ objsNum = len(FreeCAD.ActiveDocument.Objects) if FreeCAD.ActiveDocument is not None else 0
+ # pcb.makePads(shape_type='face',thickness=0.05,holes=True,fit_arcs=True) #,prefix='')
+ if not skip_import_pads:
+ pcb.makePads(shape_type="face", thickness=0.05, holes=True, fit_arcs=True) # ,prefix='')
+ if FreeCAD.ActiveDocument is not None and objsNum < len(FreeCAD.ActiveDocument.Objects):
+ pads = FreeCAD.ActiveDocument.ActiveObject
+ pads.Placement.Base.z = pads.Placement.Base.z + 2 * deltaz
+ new_obj = simple_cpy(pads, "topPads" + ftname_sfx)
+ say_time()
+ # removesubtree([pads])
+ pads.ViewObject.Visibility = False
+ add_toberemoved.append([pads])
+ topPads = new_obj
if FreeCAD.ActiveDocument is not None:
objsNum = len(FreeCAD.ActiveDocument.Objects)
# pcb.makeTracks(shape_type='face',fit_arcs=True,thickness=0.05,holes=True) #,prefix='')
# pcb.makeTracks(shape_type='face',fit_arcs=True,thickness=0.05,holes=True) #,prefix='')
- if skip_import_tracks != True:
- pcb.makeTracks(shape_type='face',fit_arcs=True,thickness=0.05,holes=False) # holes=True) #,prefix='')
- if FreeCAD.ActiveDocument is not None:
- if objsNum < len(FreeCAD.ActiveDocument.Objects):
- tracks_=FreeCAD.ActiveDocument.ActiveObject
- objsNum = len(FreeCAD.ActiveDocument.Objects)
- #print(objsNum,len(FreeCAD.ActiveDocument.Objects))
- holes=pcb.makeHoles(oval=True)
- #print(objsNum,len(FreeCAD.ActiveDocument.Objects))
- if (objsNum) < len(FreeCAD.ActiveDocument.Objects):
- drl = Draft.makeShape2DView(holes, FreeCAD.Vector(0.0, 0.0, 1.0))
- recompute_active_object()
- holesSk = Draft.makeSketch(FreeCAD.ActiveDocument.ActiveObject, autoconstraints=True)
- recompute_active_object()
- extrude_holes(holesSk,pcbThickness*3)
- holes_ = FreeCAD.ActiveDocument.ActiveObject
- cut_fuzzy(tracks_,holes_,0.00006) #6e-5 fuzzy tolerance
- holes.ViewObject.Visibility = False
- holes_.ViewObject.Visibility = False
- holesSk.ViewObject.Visibility = False
- drl.ViewObject.Visibility = False
- add_toberemoved.append([holes,holes_,holesSk,drl])
- say_time()
- tracks=FreeCAD.ActiveDocument.ActiveObject
- tracks.Placement.Base.z+=deltaz
- tracks.ViewObject.ShapeColor=mkColor(trk_col)
- new_obj = simple_cpy(tracks,'topTracks'+ftname_sfx)
- say_time()
- # removesubtree([tracks])
- tracks.ViewObject.Visibility = False
- tracks_.ViewObject.Visibility = False
- add_toberemoved.append([tracks,tracks_])
- topTracks = new_obj
- #stop
-
+ if not skip_import_tracks:
+ pcb.makeTracks(shape_type="face", fit_arcs=True, thickness=0.05, holes=False) # holes=True) #,prefix='')
+ if FreeCAD.ActiveDocument is not None and objsNum < len(FreeCAD.ActiveDocument.Objects):
+ tracks_ = FreeCAD.ActiveDocument.ActiveObject
+ objsNum = len(FreeCAD.ActiveDocument.Objects)
+ # print(objsNum,len(FreeCAD.ActiveDocument.Objects))
+ holes = pcb.makeHoles(oval=True)
+ # print(objsNum,len(FreeCAD.ActiveDocument.Objects))
+ if (objsNum) < len(FreeCAD.ActiveDocument.Objects):
+ drl = Draft.makeShape2DView(holes, FreeCAD.Vector(0.0, 0.0, 1.0))
+ recompute_active_object()
+ holesSk = Draft.makeSketch(FreeCAD.ActiveDocument.ActiveObject, autoconstraints=True)
+ recompute_active_object()
+ extrude_holes(holesSk, pcbThickness * 3)
+ holes_ = FreeCAD.ActiveDocument.ActiveObject
+ cut_fuzzy(tracks_, holes_, 0.00006) # 6e-5 fuzzy tolerance
+ holes.ViewObject.Visibility = False
+ holes_.ViewObject.Visibility = False
+ holesSk.ViewObject.Visibility = False
+ drl.ViewObject.Visibility = False
+ add_toberemoved.append([holes, holes_, holesSk, drl])
+ say_time()
+ tracks = FreeCAD.ActiveDocument.ActiveObject
+ tracks.Placement.Base.z += deltaz
+ tracks.ViewObject.ShapeColor = mkColor(trk_col)
+ new_obj = simple_cpy(tracks, "topTracks" + ftname_sfx)
+ say_time()
+ # removesubtree([tracks])
+ tracks.ViewObject.Visibility = False
+ tracks_.ViewObject.Visibility = False
+ add_toberemoved.append([tracks, tracks_])
+ topTracks = new_obj
+ # stop
+
if 0:
- ply_area=[]
- for lp in mypcb.gr_poly: #pcb area polylines
- if hasattr(lp, 'layer'):
- k_test=lp.layer
- else:
- k_test=lp.layers
- if 'F.Cu' not in k_test:
+ ply_area = []
+ for lp in mypcb.gr_poly: # pcb area polylines
+ k_test = lp.layer if hasattr(lp, "layer") else lp.layers
+ if "F.Cu" not in k_test:
continue
# print(lp, lp.fill)
- if lp.fill != 'solid':
+ if lp.fill != "solid":
continue
# print('solid')
ply_lines = []
- edges=[]
- ind = 0
l = len(lp.pts.xy)
# print(l)
- for p in lp.pts.xy:
+ for ind, p in enumerate(lp.pts.xy):
if ind == 0:
# line1=Part.Edge(PLine(FreeCAD.Base.Vector(lp.pts.xy[l-1][0],-lp.pts.xy[l-1][1],0), FreeCAD.Base.Vector(lp.pts.xy[0][0],-lp.pts.xy[0][1],0)))
# edges.append(line1);
- line2=Part.Edge(PLine(FreeCAD.Base.Vector(lp.pts.xy[l-1][0],-lp.pts.xy[l-1][1],0), FreeCAD.Base.Vector(lp.pts.xy[0][0],-lp.pts.xy[0][1],0)))
+ line2 = Part.Edge(
+ PLine(
+ FreeCAD.Base.Vector(lp.pts.xy[l - 1][0], -lp.pts.xy[l - 1][1], 0),
+ FreeCAD.Base.Vector(lp.pts.xy[0][0], -lp.pts.xy[0][1], 0),
+ ),
+ )
ply_lines.append(line2)
else:
# line1=Part.Edge(PLine(FreeCAD.Base.Vector(lp.pts.xy[ind-1][0],-lp.pts.xy[ind-1][1],0), FreeCAD.Base.Vector(lp.pts.xy[ind][0],-lp.pts.xy[ind][1],0)))
# edges.append(line1);
- line2=Part.Edge(PLine(FreeCAD.Base.Vector(lp.pts.xy[ind-1][0],-lp.pts.xy[ind-1][1],0), FreeCAD.Base.Vector(lp.pts.xy[ind][0],-lp.pts.xy[ind][1],0)))
+ line2 = Part.Edge(
+ PLine(
+ FreeCAD.Base.Vector(lp.pts.xy[ind - 1][0], -lp.pts.xy[ind - 1][1], 0),
+ FreeCAD.Base.Vector(lp.pts.xy[ind][0], -lp.pts.xy[ind][1], 0),
+ ),
+ )
ply_lines.append(line2)
- ind+=1
-
- if len(ply_lines)>0:
- #w=Part.Wire(edges)
- #Part.show(Part.Wire(edges))
- wl=Part.Wire(ply_lines)
+
+ if len(ply_lines) > 0:
+ # w=Part.Wire(edges)
+ # Part.show(Part.Wire(edges))
+ wl = Part.Wire(ply_lines)
# Part.show(Part.Wire(ply_lines))
# fc=Part.makeFace(w,'Part::FaceMakerSimple')
- fc=Part.makeFace(wl,'Part::FaceMakerSimple')
+ fc = Part.makeFace(wl, "Part::FaceMakerSimple")
ply_area.append(fc)
-
+
if len(ply_area) > 0:
Part.show(Part.makeCompound(ply_area))
- ws=[]
- wst=[]
- for j,pl in enumerate(mypcb.gr_poly): #pcb area polylines
- if hasattr(pl, 'layer'):
- k_test=pl.layer
- else:
- k_test=pl.layers
- if unquote(k_test) == 'F.Cu':
- pln=Part.Wire(make_gr_poly(pl))
- if pl.fill == 'solid':
- ws.append((pln))
- if hasattr(pl,'stroke'):
- width = pl.stroke.width
- else:
- width = pl.width
+ ws = []
+ wst = []
+ for j, pl in enumerate(mypcb.gr_poly): # pcb area polylines
+ k_test = pl.layer if hasattr(pl, "layer") else pl.layers
+ if unquote(k_test) == "F.Cu":
+ pln = Part.Wire(make_gr_poly(pl))
+ if pl.fill == "solid":
+ ws.append(pln)
+ width = pl.stroke.width if hasattr(pl, "stroke") else pl.width
for e in pln.Edges:
- #aco=_wire(e,self.layer)
- wst.append(makeThickLine(makeVect([e.Vertexes[0].X,-e.Vertexes[0].Y]),makeVect([e.Vertexes[1].X,-e.Vertexes[1].Y]),width/2.0))
+ # aco=_wire(e,self.layer)
+ wst.append(
+ makeThickLine(
+ makeVect([e.Vertexes[0].X, -e.Vertexes[0].Y]),
+ makeVect([e.Vertexes[1].X, -e.Vertexes[1].Y]),
+ width / 2.0,
+ ),
+ )
# cp = Part.makeCompound(wst+ws)
# fc=Part.makeFace(cp,'Part::FaceMakerSimple')
# Part.show(fc)
- #if len (ws)>0:
+ # if len (ws)>0:
# fc=Part.makeFace(ws,'Part::FaceMakerSimple')
# Part.show(fc)
- if len (wst)>0 or len(ws)>0:
+ if len(wst) > 0 or len(ws) > 0:
if 0:
- f=Part.makeFace(wst[0],'Part::FaceMakerSimple')
- f1=Part.makeFace(wst[1],'Part::FaceMakerSimple')
- f2=f.fuse(f1)
+ f = Part.makeFace(wst[0], "Part::FaceMakerSimple")
+ f1 = Part.makeFace(wst[1], "Part::FaceMakerSimple")
+ f2 = f.fuse(f1)
Part.show(f2)
Part.show(f)
Part.show(f1)
for w in wst[1:]:
- f.fuse(Part.makeFace(w,'Part::FaceMakerSimple'))
+ f.fuse(Part.makeFace(w, "Part::FaceMakerSimple"))
Part.show(f)
- fc=Part.makeFace(Part.makeCompound(wst+ws),'Part::FaceMakerSimple')
+ fc = Part.makeFace(Part.makeCompound(wst + ws), "Part::FaceMakerSimple")
Part.show(fc)
- print('TBD: gr_rect,gr_poly use stroke width (w makethickline)')
- #stop
- gr_rects=[]
- for r in mypcb.gr_rect: #pcb area from rect
- if hasattr(r, 'layer'):
- k_test=r.layer
- else:
- k_test=r.layers
- if 'F.Cu' not in k_test:
+ print("TBD: gr_rect,gr_poly use stroke width (w makethickline)")
+ # stop
+ gr_rects = []
+ for r in mypcb.gr_rect: # pcb area from rect
+ k_test = r.layer if hasattr(r, "layer") else r.layers
+ if "F.Cu" not in k_test:
continue
- if r.fill != 'solid':
+ if r.fill != "solid":
continue
# rct = Part.show(make_gr_rect(r))
if 0:
- l1=Part.Edge(PLine(FreeCAD.Base.Vector(r.start[0],-r.start[1],0), FreeCAD.Base.Vector(r.end[0],-r.start[1],0)))
- l2=Part.Edge(PLine(FreeCAD.Base.Vector(r.end[0],-r.start[1],0), FreeCAD.Base.Vector(r.end[0],-r.end[1],0)))
- l3=Part.Edge(PLine(FreeCAD.Base.Vector(r.end[0],-r.end[1],0), FreeCAD.Base.Vector(r.start[0],-r.end[1],0)))
- l4=Part.Edge(PLine(FreeCAD.Base.Vector(r.start[0],-r.end[1],0), FreeCAD.Base.Vector(r.start[0],-r.start[1],0)))
- w=Part.Wire([l1,l2,l3,l4])
- #Part.show(w)
- fc=Part.makeFace(w,'Part::FaceMakerSimple')
- #Part.show(fc)
+ l1 = Part.Edge(
+ PLine(
+ FreeCAD.Base.Vector(r.start[0], -r.start[1], 0),
+ FreeCAD.Base.Vector(r.end[0], -r.start[1], 0),
+ ),
+ )
+ l2 = Part.Edge(
+ PLine(FreeCAD.Base.Vector(r.end[0], -r.start[1], 0), FreeCAD.Base.Vector(r.end[0], -r.end[1], 0)),
+ )
+ l3 = Part.Edge(
+ PLine(FreeCAD.Base.Vector(r.end[0], -r.end[1], 0), FreeCAD.Base.Vector(r.start[0], -r.end[1], 0)),
+ )
+ l4 = Part.Edge(
+ PLine(
+ FreeCAD.Base.Vector(r.start[0], -r.end[1], 0),
+ FreeCAD.Base.Vector(r.start[0], -r.start[1], 0),
+ ),
+ )
+ w = Part.Wire([l1, l2, l3, l4])
+ # Part.show(w)
+ fc = Part.makeFace(w, "Part::FaceMakerSimple")
+ # Part.show(fc)
gr_rects.append(fc)
- fc = Part.makeFace(make_gr_rect(r),'Part::FaceMakerSimple')
+ fc = Part.makeFace(make_gr_rect(r), "Part::FaceMakerSimple")
gr_rects.append(fc)
if len(gr_rects) > 0:
Part.show(Part.makeCompound(gr_rects))
-
- gr_circles=[]
- for c in mypcb.gr_circle: #pcb area from circles
- if hasattr(c, 'layer'):
- k_test=c.layer
- else:
- k_test=c.layers
- if 'F.Cu' not in k_test:
+
+ gr_circles = []
+ for c in mypcb.gr_circle: # pcb area from circles
+ k_test = c.layer if hasattr(c, "layer") else c.layers
+ if "F.Cu" not in k_test:
+ continue
+ if c.fill != "solid":
continue
- if c.fill != 'solid':
- continue
width = c.stroke.width
center = makeVect(c.center)
end = makeVect(c.end)
r = center.distanceToPoint(end)
- c = FreeCAD.Base.Vector(0,0,0)
- d = FreeCAD.Base.Vector(0,0,1)
- cr1=(Part.makeFace(Part.makeCircle(r+width*0.5, center),'Part::FaceMakerSimple'))
+ c = FreeCAD.Base.Vector(0, 0, 0)
+ FreeCAD.Base.Vector(0, 0, 1)
+ cr1 = Part.makeFace(Part.makeCircle(r + width * 0.5, center), "Part::FaceMakerSimple")
gr_circles.append(cr1)
if len(gr_circles) > 0:
Part.show(Part.makeCompound(gr_circles))
-
- print('TBD: gr_rect,gr_poly use stroke width (w makethickline), FC build date')
- #stop
-
+
+ print("TBD: gr_rect,gr_poly use stroke width (w makethickline), FC build date")
+ # stop
+
if FreeCAD.ActiveDocument is not None:
objsNum = len(FreeCAD.ActiveDocument.Objects)
- #pcb.makeZones(shape_type='face',thickness=0.05, fit_arcs=True,holes=True) #,prefix='')
- if skip_import_zones != True:
- pcb.makeZones(shape_type='face',thickness=0.05, fit_arcs=True,holes=True) #,prefix='')
+ # pcb.makeZones(shape_type='face',thickness=0.05, fit_arcs=True,holes=True) #,prefix='')
+ if not skip_import_zones:
+ pcb.makeZones(shape_type="face", thickness=0.05, fit_arcs=True, holes=True) # ,prefix='')
if FreeCAD.ActiveDocument is not None:
if objsNum < len(FreeCAD.ActiveDocument.Objects):
say_time()
- zones=FreeCAD.ActiveDocument.ActiveObject
- zones.Placement.Base.z+=deltaz
- new_obj = simple_cpy(zones,'topZones'+ftname_sfx)
+ zones = FreeCAD.ActiveDocument.ActiveObject
+ zones.Placement.Base.z += deltaz
+ new_obj = simple_cpy(zones, "topZones" + ftname_sfx)
say_time()
# removesubtree([zones])
zones.ViewObject.Visibility = False
add_toberemoved.append([zones])
topZones = new_obj
- if len (FreeCAD.ActiveDocument.getObjectsByLabel('Pcb'+ftname_sfx)) >0:
- #PCB_Sketch_5737
+ if len(FreeCAD.ActiveDocument.getObjectsByLabel("Pcb" + ftname_sfx)) > 0:
+ # PCB_Sketch_5737
# pcb_sk = FreeCAD.ActiveDocument.getObject('PCB_Sketch'+ftname_sfx)
- pcb_ = FreeCAD.ActiveDocument.getObject('Pcb'+ftname_sfx)
- area_max=0
- f_max=''
+ pcb_ = FreeCAD.ActiveDocument.getObject("Pcb" + ftname_sfx)
+ area_max = 0
+ f_max = ""
for f in pcb_.Shape.Faces:
# print (f.Area)
if f.Area > area_max:
- area_max=f.Area
- f_max=f
- #print (area_max)
- #print('area_max=',area_max)
+ area_max = f.Area
+ f_max = f
+ # print (area_max)
+ # print('area_max=',area_max)
### check if BBOx pcb > BBOx tracks
# Part.show(f_max.OuterWire)
- #Part.show(Part.makeFace(f_max.OuterWire,'Part::FaceMakerSimple').extrude(FreeCAD.Vector(0.0, 0.0, -pcbThickness)))
- if 0: #max lenth esternal perimeter
- l_max=0
- w_max=''
+ # Part.show(Part.makeFace(f_max.OuterWire,'Part::FaceMakerSimple').extrude(FreeCAD.Vector(0.0, 0.0, -pcbThickness)))
+ if 0: # max lenth esternal perimeter
+ l_max = 0
+ w_max = ""
for w in f_max.Wires:
if w.Length > l_max:
- l_max=w.Length
- w_max=w
- pcb_sk = Draft.makeSketch(w_max,autoconstraints=True)
- FC_majorV,FC_minorV,FC_git_Nbr=getFCversion()
- if FC_majorV>=0 and FC_minorV>=21:
- pcb_sk = Draft.makeSketch(f_max,autoconstraints=True)
- if hasattr(pcb_sk,'RedundantConstraints'):
- #pcb_sk.autoRemoveRedundants(True)
- #pcb_sk.solve()
- FreeCAD.ActiveDocument.recompute()
- if len (pcb_sk.RedundantConstraints)>0:
- print('fixing over constrained sketch')
- new_constrains=[]
- list1 = pcb_sk.Constraints
- index_list=pcb_sk.RedundantConstraints
+ l_max = w.Length
+ w_max = w
+ pcb_sk = Draft.makeSketch(w_max, autoconstraints=True)
+ FC_majorV, FC_minorV, _FC_git_Nbr = getFCversion()
+ if FC_majorV >= 0 and FC_minorV >= 21:
+ pcb_sk = Draft.makeSketch(f_max, autoconstraints=True)
+ if hasattr(pcb_sk, "RedundantConstraints"):
+ # pcb_sk.autoRemoveRedundants(True)
+ # pcb_sk.solve()
+ FreeCAD.ActiveDocument.recompute()
+ if len(pcb_sk.RedundantConstraints) > 0:
+ print("fixing over constrained sketch")
+ new_constrains = []
+ list1 = pcb_sk.Constraints
+ index_list = pcb_sk.RedundantConstraints
for i in range(len(index_list)):
index_list[i] -= 1
- index_set = set(index_list) # optional but faster
- new_constrains=[x for i, x in enumerate(list1) if i not in index_set]
- pcb_sk.Constraints=new_constrains
+ index_set = set(index_list) # optional but faster
+ new_constrains = [x for i, x in enumerate(list1) if i not in index_set]
+ pcb_sk.Constraints = new_constrains
FreeCAD.ActiveDocument.recompute()
- # pcb_sk = Draft.makeSketch(f_max.OuterWire,autoconstraints=True) # esternal perimeter
+ # pcb_sk = Draft.makeSketch(f_max.OuterWire,autoconstraints=True) # esternal perimeter
else:
- FreeCAD.Console.PrintWarning('Sketch attrib \'RedundantConstraints\' missing\n')
+ FreeCAD.Console.PrintWarning("Sketch attrib 'RedundantConstraints' missing\n")
FreeCAD.ActiveDocument.removeObject(pcb_sk.Name)
- pcb_sk = Draft.makeSketch(f_max,autoconstraints=False)
+ pcb_sk = Draft.makeSketch(f_max, autoconstraints=False)
FreeCAD.ActiveDocument.recompute()
else:
- pcb_sk = Draft.makeSketch(f_max,autoconstraints=False)
+ pcb_sk = Draft.makeSketch(f_max, autoconstraints=False)
FreeCAD.ActiveDocument.recompute()
-
+
add_toberemoved.append([pcb_sk])
-
- #stop
+
+ # stop
if topPads is not None:
- topPads.Placement = FreeCAD.ActiveDocument.getObject('Pcb'+ftname_sfx).Placement
- #if (topPads.Shape.BoundBox.XLength > pcb_sk.Shape.BoundBox.XLength) or \
+ topPads.Placement = FreeCAD.ActiveDocument.getObject("Pcb" + ftname_sfx).Placement
+ # if (topPads.Shape.BoundBox.XLength > pcb_sk.Shape.BoundBox.XLength) or \
# (topPads.Shape.BoundBox.YLength > pcb_sk.Shape.BoundBox.YLength):
-
- if (topPads.Shape.BoundBox.XMax > pcb_sk.Shape.BoundBox.XMax) or \
- (topPads.Shape.BoundBox.XMin < pcb_sk.Shape.BoundBox.XMin) or \
- (topPads.Shape.BoundBox.YMax > pcb_sk.Shape.BoundBox.YMax) or \
- (topPads.Shape.BoundBox.YMin < pcb_sk.Shape.BoundBox.YMin):
- topPads_cut_Name, temp_tobedeleted = cut_out_tracks(pcb_sk,topPads,ftname_sfx)
+
+ if (
+ (topPads.Shape.BoundBox.XMax > pcb_sk.Shape.BoundBox.XMax)
+ or (topPads.Shape.BoundBox.XMin < pcb_sk.Shape.BoundBox.XMin)
+ or (topPads.Shape.BoundBox.YMax > pcb_sk.Shape.BoundBox.YMax)
+ or (topPads.Shape.BoundBox.YMin < pcb_sk.Shape.BoundBox.YMin)
+ ):
+ topPads_cut_Name, temp_tobedeleted = cut_out_tracks(pcb_sk, topPads, ftname_sfx)
topPads = FreeCAD.ActiveDocument.getObject(topPads_cut_Name)
- print('TBD pcb sketch open due to edgecuts in fp')
+ print("TBD pcb sketch open due to edgecuts in fp")
# Part.show(App.ActiveDocument.Cut.Shape.Faces[64].OuterWire)
add_toberemoved.append(temp_tobedeleted)
- topPads.Placement.Base.z+=2*deltaz
+ topPads.Placement.Base.z += 2 * deltaz
if topTracks is not None:
- topTracks.Placement = FreeCAD.ActiveDocument.getObject('Pcb'+ftname_sfx).Placement
- topTracks.Placement.Base.z+=deltaz
+ topTracks.Placement = FreeCAD.ActiveDocument.getObject("Pcb" + ftname_sfx).Placement
+ topTracks.Placement.Base.z += deltaz
if topZones is not None:
- topZones.Placement = FreeCAD.ActiveDocument.getObject('Pcb'+ftname_sfx).Placement
- topZones.Placement.Base.z+=deltaz
- if len (FreeCAD.ActiveDocument.getObjectsByLabel('Board_Geoms'+ftname_sfx)) > 0:
+ topZones.Placement = FreeCAD.ActiveDocument.getObject("Pcb" + ftname_sfx).Placement
+ topZones.Placement.Base.z += deltaz
+ if len(FreeCAD.ActiveDocument.getObjectsByLabel("Board_Geoms" + ftname_sfx)) > 0:
if use_AppPart and not use_LinkGroups:
if topPads is not None:
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+ftname_sfx).addObject(topPads)
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).addObject(topPads)
if topTracks is not None:
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+ftname_sfx).addObject(topTracks)
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).addObject(topTracks)
if topZones is not None:
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+ftname_sfx).addObject(topZones)
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).addObject(topZones)
elif use_LinkGroups:
if topPads is not None:
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+ftname_sfx).ViewObject.dropObject(topPads,topPads,'',[])
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).ViewObject.dropObject(
+ topPads,
+ topPads,
+ "",
+ [],
+ )
if topTracks is not None:
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+ftname_sfx).ViewObject.dropObject(topTracks,topTracks,'',[])
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).ViewObject.dropObject(
+ topTracks,
+ topTracks,
+ "",
+ [],
+ )
if topZones is not None:
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+ftname_sfx).ViewObject.dropObject(topZones,topZones,'',[])
- #try: #doing bot tracks layer
- #pcb.setLayer(LvlBotName)
- #stop
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).ViewObject.dropObject(
+ topZones,
+ topZones,
+ "",
+ [],
+ )
+ # try: #doing bot tracks layer
+ # pcb.setLayer(LvlBotName)
+ # stop
pcb.setLayer(Bot_lvl)
# pcb.makeCopper(holes=True, minSize=minSizeDrill)
- #pcb.makeCopper(holes=True)
+ # pcb.makeCopper(holes=True)
botPads = None
botTracks = None
botZones = None
- if FreeCAD.ActiveDocument is not None:
- objsNum = len(FreeCAD.ActiveDocument.Objects)
- else:
- objsNum = 0
- #pcb.makePads(shape_type='face',thickness=0.05,holes=True,fit_arcs=True,prefix='')
- if skip_import_pads != True:
- pcb.makePads(shape_type='face',thickness=0.05,holes=True,fit_arcs=True) #,prefix='')
- if FreeCAD.ActiveDocument is not None:
- if objsNum < len(FreeCAD.ActiveDocument.Objects):
- doc=FreeCAD.ActiveDocument
- padsB=FreeCAD.ActiveDocument.ActiveObject
- padsB.Placement.Base.z = padsB.Placement.Base.z - (pcbThickness + 2*deltaz)
- new_obj = simple_cpy(padsB,'botPads'+ftname_sfx)
- say_time()
- # removesubtree([pads])
- padsB.ViewObject.Visibility = False
- add_toberemoved.append([padsB])
- botPads = new_obj
+ objsNum = len(FreeCAD.ActiveDocument.Objects) if FreeCAD.ActiveDocument is not None else 0
+ # pcb.makePads(shape_type='face',thickness=0.05,holes=True,fit_arcs=True,prefix='')
+ if not skip_import_pads:
+ pcb.makePads(shape_type="face", thickness=0.05, holes=True, fit_arcs=True) # ,prefix='')
+ if FreeCAD.ActiveDocument is not None and objsNum < len(FreeCAD.ActiveDocument.Objects):
+ padsB = FreeCAD.ActiveDocument.ActiveObject
+ padsB.Placement.Base.z = padsB.Placement.Base.z - (pcbThickness + 2 * deltaz)
+ new_obj = simple_cpy(padsB, "botPads" + ftname_sfx)
+ say_time()
+ # removesubtree([pads])
+ padsB.ViewObject.Visibility = False
+ add_toberemoved.append([padsB])
+ botPads = new_obj
if FreeCAD.ActiveDocument is not None:
objsNum = len(FreeCAD.ActiveDocument.Objects)
# pcb.makeTracks(shape_type='face',fit_arcs=True,thickness=0.05,holes=True,prefix='')
- if skip_import_tracks != True:
- pcb.makeTracks(shape_type='face',fit_arcs=True,thickness=0.05,holes=False) # holes=True) #,prefix='')
- if FreeCAD.ActiveDocument is not None:
- if objsNum < len(FreeCAD.ActiveDocument.Objects):
- tracksB_=FreeCAD.ActiveDocument.ActiveObject
- objsNum = len(FreeCAD.ActiveDocument.Objects)
- holesB=pcb.makeHoles(oval=True)
- if (objsNum) < len(FreeCAD.ActiveDocument.Objects):
- drlB = Draft.makeShape2DView(holesB, FreeCAD.Vector(0.0, 0.0, 1.0))
- recompute_active_object()
- holesSkB = Draft.makeSketch(FreeCAD.ActiveDocument.ActiveObject, autoconstraints=True)
- recompute_active_object()
- extrude_holes(holesSkB,pcbThickness*3)
- holesB_ = FreeCAD.ActiveDocument.ActiveObject
- cut_fuzzy(tracksB_,holesB_,0.00006) #6e-5 fuzzy tolerance
- holesB.ViewObject.Visibility = False
- holesB_.ViewObject.Visibility = False
- holesSkB.ViewObject.Visibility = False
- drlB.ViewObject.Visibility = False
- add_toberemoved.append([holesB,holesB_,holesSkB,drlB])
- say_time()
- tracksB=FreeCAD.ActiveDocument.ActiveObject
- tracksB.Placement.Base.z-=(pcbThickness + deltaz)
- tracksB.ViewObject.ShapeColor=mkColor(trk_col)
- new_obj = simple_cpy(tracksB,'botTracks'+ftname_sfx)
- say_time()
- # removesubtree([tracks])
- tracksB.ViewObject.Visibility = False
- tracksB_.ViewObject.Visibility = False
- add_toberemoved.append([tracksB,tracksB_])
- botTracks = new_obj
- #stop
+ if not skip_import_tracks:
+ pcb.makeTracks(shape_type="face", fit_arcs=True, thickness=0.05, holes=False) # holes=True) #,prefix='')
+ if FreeCAD.ActiveDocument is not None and objsNum < len(FreeCAD.ActiveDocument.Objects):
+ tracksB_ = FreeCAD.ActiveDocument.ActiveObject
+ objsNum = len(FreeCAD.ActiveDocument.Objects)
+ holesB = pcb.makeHoles(oval=True)
+ if (objsNum) < len(FreeCAD.ActiveDocument.Objects):
+ drlB = Draft.makeShape2DView(holesB, FreeCAD.Vector(0.0, 0.0, 1.0))
+ recompute_active_object()
+ holesSkB = Draft.makeSketch(FreeCAD.ActiveDocument.ActiveObject, autoconstraints=True)
+ recompute_active_object()
+ extrude_holes(holesSkB, pcbThickness * 3)
+ holesB_ = FreeCAD.ActiveDocument.ActiveObject
+ cut_fuzzy(tracksB_, holesB_, 0.00006) # 6e-5 fuzzy tolerance
+ holesB.ViewObject.Visibility = False
+ holesB_.ViewObject.Visibility = False
+ holesSkB.ViewObject.Visibility = False
+ drlB.ViewObject.Visibility = False
+ add_toberemoved.append([holesB, holesB_, holesSkB, drlB])
+ say_time()
+ tracksB = FreeCAD.ActiveDocument.ActiveObject
+ tracksB.Placement.Base.z -= pcbThickness + deltaz
+ tracksB.ViewObject.ShapeColor = mkColor(trk_col)
+ new_obj = simple_cpy(tracksB, "botTracks" + ftname_sfx)
+ say_time()
+ # removesubtree([tracks])
+ tracksB.ViewObject.Visibility = False
+ tracksB_.ViewObject.Visibility = False
+ add_toberemoved.append([tracksB, tracksB_])
+ botTracks = new_obj
+ # stop
if FreeCAD.ActiveDocument is not None:
objsNum = len(FreeCAD.ActiveDocument.Objects)
- #pcb.makeZones(shape_type='face',thickness=0.05, fit_arcs=True,holes=True) # ,prefix='')
- if skip_import_zones != True:
- pcb.makeZones(shape_type='face',thickness=0.05, fit_arcs=True,holes=True) # ,prefix='')
+ # pcb.makeZones(shape_type='face',thickness=0.05, fit_arcs=True,holes=True) # ,prefix='')
+ if not skip_import_zones:
+ pcb.makeZones(shape_type="face", thickness=0.05, fit_arcs=True, holes=True) # ,prefix='')
if FreeCAD.ActiveDocument is not None:
if objsNum < len(FreeCAD.ActiveDocument.Objects):
say_time()
- zonesB=FreeCAD.ActiveDocument.ActiveObject
+ zonesB = FreeCAD.ActiveDocument.ActiveObject
zonesB.Placement.Base.z = zonesB.Placement.Base.z - (pcbThickness + deltaz)
- new_obj = simple_cpy(zonesB,'botZones'+ftname_sfx)
+ new_obj = simple_cpy(zonesB, "botZones" + ftname_sfx)
say_time()
# removesubtree([zones])
zonesB.ViewObject.Visibility = False
add_toberemoved.append([zonesB])
botZones = new_obj
- if len (FreeCAD.ActiveDocument.getObjectsByLabel('Pcb'+ftname_sfx)) >0:
- #PCB_Sketch_5737
+ if len(FreeCAD.ActiveDocument.getObjectsByLabel("Pcb" + ftname_sfx)) > 0:
+ # PCB_Sketch_5737
# pcb_sk = FreeCAD.ActiveDocument.getObject('PCB_Sketch'+ftname_sfx)
if pcb_sk is None:
- pcb_ = FreeCAD.ActiveDocument.getObject('Pcb'+ftname_sfx)
- area_max=0
- f_max=''
+ pcb_ = FreeCAD.ActiveDocument.getObject("Pcb" + ftname_sfx)
+ area_max = 0
+ f_max = ""
for f in pcb_.Shape.Faces:
# print (f.Area)
if f.Area > area_max:
- area_max=f.Area
- f_max=f
+ area_max = f.Area
+ f_max = f
# print (area_max)
# print('area_max=',area_max)
### check if BBOx pcb > BBOx tracks
# Part.show(f_max.OuterWire)
- #Part.show(Part.makeFace(f_max.OuterWire,'Part::FaceMakerSimple').extrude(FreeCAD.Vector(0.0, 0.0, -pcbThickness)))
+ # Part.show(Part.makeFace(f_max.OuterWire,'Part::FaceMakerSimple').extrude(FreeCAD.Vector(0.0, 0.0, -pcbThickness)))
# pcb_sk = Draft.makeSketch(f_max.OuterWire,autoconstraints=True) # external perimeter
- pcb_sk = Draft.makeSketch(f_max,autoconstraints=True)
- #pcb_sk = Draft.makeSketch(f_max,autoconstraints=False)
- FreeCAD.ActiveDocument.recompute()
- if len (pcb_sk.RedundantConstraints)>0:
- #stop
- new_constrains=[]
- list1 = pcb_sk.Constraints
- index_list=pcb_sk.RedundantConstraints
+ pcb_sk = Draft.makeSketch(f_max, autoconstraints=True)
+ # pcb_sk = Draft.makeSketch(f_max,autoconstraints=False)
+ FreeCAD.ActiveDocument.recompute()
+ if len(pcb_sk.RedundantConstraints) > 0:
+ # stop
+ new_constrains = []
+ list1 = pcb_sk.Constraints
+ index_list = pcb_sk.RedundantConstraints
for i in range(len(index_list)):
index_list[i] -= 1
- index_set = set(index_list) # optional but faster
- new_constrains=[x for i, x in enumerate(list1) if i not in index_set]
- pcb_sk.Constraints=new_constrains
+ index_set = set(index_list) # optional but faster
+ new_constrains = [x for i, x in enumerate(list1) if i not in index_set]
+ pcb_sk.Constraints = new_constrains
FreeCAD.ActiveDocument.recompute()
add_toberemoved.append([pcb_sk])
### check if BBOx pcb > BBOx tracks
if botPads is not None:
- botPads.Placement = FreeCAD.ActiveDocument.getObject('Pcb'+ftname_sfx).Placement
- #if (botPads.Shape.BoundBox.XLength > pcb_sk.Shape.BoundBox.XLength) or \
+ botPads.Placement = FreeCAD.ActiveDocument.getObject("Pcb" + ftname_sfx).Placement
+ # if (botPads.Shape.BoundBox.XLength > pcb_sk.Shape.BoundBox.XLength) or \
# (botPads.Shape.BoundBox.YLength > pcb_sk.Shape.BoundBox.YLength):
- if (botPads.Shape.BoundBox.XMax > pcb_sk.Shape.BoundBox.XMax) or \
- (botPads.Shape.BoundBox.XMin < pcb_sk.Shape.BoundBox.XMin) or \
- (botPads.Shape.BoundBox.YMax > pcb_sk.Shape.BoundBox.YMax) or \
- (botPads.Shape.BoundBox.YMin < pcb_sk.Shape.BoundBox.YMin):
- botPads_cut_Name, temp_tobedeleted = cut_out_tracks(pcb_sk,botPads,ftname_sfx)
+ if (
+ (botPads.Shape.BoundBox.XMax > pcb_sk.Shape.BoundBox.XMax)
+ or (botPads.Shape.BoundBox.XMin < pcb_sk.Shape.BoundBox.XMin)
+ or (botPads.Shape.BoundBox.YMax > pcb_sk.Shape.BoundBox.YMax)
+ or (botPads.Shape.BoundBox.YMin < pcb_sk.Shape.BoundBox.YMin)
+ ):
+ botPads_cut_Name, temp_tobedeleted = cut_out_tracks(pcb_sk, botPads, ftname_sfx)
botPads = FreeCAD.ActiveDocument.getObject(botPads_cut_Name)
add_toberemoved.append(temp_tobedeleted)
- botPads.Placement.Base.z-=pcbThickness+2*deltaz
+ botPads.Placement.Base.z -= pcbThickness + 2 * deltaz
if botTracks is not None:
- botTracks.Placement = FreeCAD.ActiveDocument.getObject('Pcb'+ftname_sfx).Placement
- botTracks.Placement.Base.z-=pcbThickness+deltaz
+ botTracks.Placement = FreeCAD.ActiveDocument.getObject("Pcb" + ftname_sfx).Placement
+ botTracks.Placement.Base.z -= pcbThickness + deltaz
if botZones is not None:
- botZones.Placement = FreeCAD.ActiveDocument.getObject('Pcb'+ftname_sfx).Placement
- botZones.Placement.Base.z-=pcbThickness+deltaz
- if len (FreeCAD.ActiveDocument.getObjectsByLabel('Board_Geoms'+ftname_sfx)) > 0:
+ botZones.Placement = FreeCAD.ActiveDocument.getObject("Pcb" + ftname_sfx).Placement
+ botZones.Placement.Base.z -= pcbThickness + deltaz
+ if len(FreeCAD.ActiveDocument.getObjectsByLabel("Board_Geoms" + ftname_sfx)) > 0:
if use_AppPart and not use_LinkGroups:
if botPads is not None:
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+ftname_sfx).addObject(botPads)
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).addObject(botPads)
if botTracks is not None:
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+ftname_sfx).addObject(botTracks)
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).addObject(botTracks)
if botZones is not None:
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+ftname_sfx).addObject(botZones)
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).addObject(botZones)
elif use_LinkGroups:
if botPads is not None:
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+ftname_sfx).ViewObject.dropObject(botPads,botPads,'',[])
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).ViewObject.dropObject(
+ botPads,
+ botPads,
+ "",
+ [],
+ )
if botTracks is not None:
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+ftname_sfx).ViewObject.dropObject(botTracks,botTracks,'',[])
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).ViewObject.dropObject(
+ botTracks,
+ botTracks,
+ "",
+ [],
+ )
if botZones is not None:
- FreeCAD.ActiveDocument.getObject('Board_Geoms'+ftname_sfx).ViewObject.dropObject(botZones,botZones,'',[])
- if skip_import_zones == True:
- FreeCAD.Console.PrintWarning('import Zone(s) skipped'+'\n')
- if skip_import_tracks == True:
- FreeCAD.Console.PrintWarning('import Track(s) skipped'+'\n')
- if skip_import_pads == True:
- FreeCAD.Console.PrintWarning('import Pad(s) skipped'+'\n')
- if skip_import_zones == True and skip_import_tracks == True and skip_import_pads == True:
- FreeCAD.Console.PrintError('importing Zones, Tracks and Pads are skipped because of settings'+'\n')
+ FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).ViewObject.dropObject(
+ botZones,
+ botZones,
+ "",
+ [],
+ )
+ if skip_import_zones:
+ FreeCAD.Console.PrintWarning("import Zone(s) skipped" + "\n")
+ if skip_import_tracks:
+ FreeCAD.Console.PrintWarning("import Track(s) skipped" + "\n")
+ if skip_import_pads:
+ FreeCAD.Console.PrintWarning("import Pad(s) skipped" + "\n")
+ if skip_import_zones and skip_import_tracks and skip_import_pads:
+ FreeCAD.Console.PrintError("importing Zones, Tracks and Pads are skipped because of settings" + "\n")
QtGui.QApplication.restoreOverrideCursor()
- msg="""importing Zones, Tracks and Pads are skipped because of settings!
"""
- msg1="ERROR! ..."
+ msg = """importing Zones, Tracks and Pads are skipped because of settings!
"""
+ msg1 = "ERROR! ..."
QtGui.QApplication.restoreOverrideCursor()
- #RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
- diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical,
- msg1,
- msg)
+ # RotateXYZGuiClass().setGeometry(25, 250, 500, 500)
+ diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical, msg1, msg)
diag.setWindowModality(QtCore.Qt.ApplicationModal)
diag.exec_()
say_time()
-
+
if FreeCAD.ActiveDocument is not None:
FreeCADGui.SendMsgToActiveView("ViewFit")
# FreeCADGui.ActiveDocument.ActiveView.setAxisCross(True)
# FreeCADGui.ActiveDocument.activeView().viewAxonometric()
return add_toberemoved
+ return None
+
+
###
diff --git a/utf8test.py b/utf8test.py
index a1c186b..0909614 100644
--- a/utf8test.py
+++ b/utf8test.py
@@ -1,100 +1,75 @@
#!/usr/bin/python
-# -*- coding: utf-8 -*-
+
+import os
import FreeCAD
-import sys, os, re
+
def check_type(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- print('string')
- return
- else:
- print('not string')
- return
- else: #py2
- if type(input) != unicode:
- print('string py2')
- return
- else:
- print('not string py2')
- return
+ if isinstance(input, str):
+ print("string")
+ return
+ print("not string")
+
def make_string(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.encode('utf-8')
- return input
- else: #py2
- if type(input) == unicode:
- input = input.encode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.encode("utf-8")
+
def make_unicode(input):
- if (sys.version_info > (3, 0)): #py3
- if isinstance(input, str):
- return input
- else:
- input = input.decode('utf-8')
- return input
- else: #py2
- if type(input) != unicode:
- input = input.decode('utf-8')
- return input
- else:
- return input
+ if isinstance(input, str):
+ return input
+ return input.decode("utf-8")
+
+
##
prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui")
-models3D_prefix = prefs.GetString('prefix3d_1')
-print (models3D_prefix)
+models3D_prefix = prefs.GetString("prefix3d_1")
+print(models3D_prefix)
check_type(models3D_prefix)
pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp")
last_pcb_path = pg.GetString("last_pcb_path")
print(last_pcb_path)
-pg.SetString("last_pcb_path",make_string(models3D_prefix))
-print ('writing done')
+pg.SetString("last_pcb_path", make_string(models3D_prefix))
+print("writing done")
check_type(last_pcb_path)
-model1 = '10rx.wrl'
-model_u=u'Würfel1.stp'
+model1 = "10rx.wrl"
+model_u = "Würfel1.stp"
fullpath = os.path.join(make_unicode(last_pcb_path), make_unicode(model_u))
-#fullpath3 = os.path.join(last_pcb_path, model_u)
-print (fullpath)
+# fullpath3 = os.path.join(last_pcb_path, model_u)
+print(fullpath)
check_type(fullpath)
newfullpath2 = make_unicode(fullpath)
-print (newfullpath2)
+print(newfullpath2)
check_type(newfullpath2)
if os.path.exists(newfullpath2):
- print('file found MAKE UNICODE')
+ print("file found MAKE UNICODE")
else:
- print ('ERROR')
+ print("ERROR")
-#fullpath = re.sub("\\", "/", fullpath)
-fullpath = fullpath.replace('\\','/')
-print (fullpath)
+# fullpath = re.sub("\\", "/", fullpath)
+fullpath = fullpath.replace("\\", "/")
+print(fullpath)
check_type(fullpath)
if os.path.exists(fullpath):
- print('file found')
+ print("file found")
else:
- print ('ERROR')
+ print("ERROR")
newfullpath = make_string(fullpath)
-print (newfullpath)
+print(newfullpath)
check_type(newfullpath)
if os.path.exists(newfullpath):
- print('file found')
+ print("file found")
else:
- print ('ERROR')
+ print("ERROR")
-fullpath = fullpath.replace('/','\\')
-print (fullpath)
+fullpath = fullpath.replace("/", "\\")
+print(fullpath)
check_type(fullpath)
if os.path.exists(fullpath):
- print('file found')
+ print("file found")
else:
- print ('ERROR')
-
-
\ No newline at end of file
+ print("ERROR")