From 97650ddfa299e2c61224d38364233e8fec296f2c Mon Sep 17 00:00:00 2001 From: vlordier Date: Fri, 1 May 2026 01:28:21 +0200 Subject: [PATCH 1/3] config: add pyproject.toml (ruff, ty, uv), pre-commit, CI, dependabot, editorconfig - pyproject.toml: ruff lint + format (py311, 120 cols, 20 rule sets), ty type checker, uv config - .pre-commit-config.yaml: ruff lint/fix + ruff-format + ty + standard hooks - .github/workflows/ci.yml: 3 jobs (ruff lint+format, pre-commit, ty) - .github/dependabot.yml: weekly updates for actions and pip - .editorconfig: 4-space indent, LF, UTF-8 - .gitattributes: LF normalization, binary file markers - .gitignore: ruff_cache, __pycache__, uv, editor temp files - .git-blame-ignore-revs: record formatting commit for git blame skip --- .editorconfig | 18 ++++++ .git-blame-ignore-revs | 4 ++ .gitattributes | 38 ++++++------ .github/dependabot.yml | 18 ++++++ .github/workflows/ci.yml | 45 +++++++++++++++ .gitignore | 13 ++++- .pre-commit-config.yaml | 34 +++++++++++ pyproject.toml | 122 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 274 insertions(+), 18 deletions(-) create mode 100644 .editorconfig create mode 100644 .git-blame-ignore-revs create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/ci.yml create mode 100644 .pre-commit-config.yaml create mode 100644 pyproject.toml 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..f670b88 --- /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. +fa87e852980125a86d918ebaea65f0576c92455f 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/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" + + From 7cb8760ab934810f2f1f55365dc2b4b59794d237 Mon Sep 17 00:00:00 2001 From: vlordier Date: Fri, 1 May 2026 01:33:44 +0200 Subject: [PATCH 2/3] format: ruff format + ruff check --fix on all Python files Apply ruff format (4-space indent, double quotes, 120 cols) and ruff check --fix + --unsafe-fixes across all 23 first-party .py files. Includes: import sorting, f-strings, trailing whitespace, useless semicolons, comprehension simplifications (C416/C419), needless-bool (SIM103), isinstance merges (SIM101), manual-list-copy (PERF402), trailing commas (COM812), and more. Third-party submodules (fcad_parser/, dxf_parser/) excluded. --- Init.py | 34 +- InitGui.py | 669 +- SaveSettings.py | 50 +- TranslateUtils.py | 3 +- ZipStepImport.py | 184 +- _DXF_Import.py | 84 +- commits_num.py | 74 +- constrainator.py | 570 +- exchangePositions.py | 1151 +- expTree.py | 67 +- explode.py | 301 +- fps.py | 927 +- hlp.py | 8 +- kicadStepUpCMD.py | 6063 +++++---- kicadStepUptools.py | 28232 +++++++++++++++++++++++------------------ kicad_parser.py | 2413 ++-- ksu_locator.py | 33 +- makefacedxf.py | 354 +- selection2edges.py | 144 +- step_amend.py | 113 +- test-mb.py | 172 +- tracks.py | 1074 +- utf8test.py | 106 +- 23 files changed, 23712 insertions(+), 19114 deletions(-) diff --git a/Init.py b/Init.py index e2cf6fc..3547f25 100644 --- a/Init.py +++ b/Init.py @@ -1,29 +1,27 @@ -#-*- 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 * +# * * # 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..a1905e5 100644 --- a/InitGui.py +++ b/InitGui.py @@ -1,62 +1,57 @@ -# -*- 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 +63,48 @@ # 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.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") + 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") + ## - 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)) + 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 + 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) + 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..1455414 100644 --- a/TranslateUtils.py +++ b/TranslateUtils.py @@ -1,4 +1,3 @@ -# -*- coding: utf8 -*- # *************************************************************************** # * * @@ -36,4 +35,4 @@ def QT_TRANSLATE_NOOP(ctx, txt): if hasattr(FreeCAD, "Qt"): translate = FreeCAD.Qt.translate else: - from DraftTools import translate + pass diff --git a/ZipStepImport.py b/ZipStepImport.py index 2b1ea0d..602f1a1 100644 --- a/ZipStepImport.py +++ b/ZipStepImport.py @@ -1,44 +1,47 @@ -# -*- 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 + +import FreeCAD ___ZipVersion___ = "1.0.5" try: - import __builtin__ as builtin #py2 + pass # py2 except: - import builtins as builtin #py3 + pass # py3 -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 +52,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 +68,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..1497efa 100644 --- a/_DXF_Import.py +++ b/_DXF_Import.py @@ -1,44 +1,45 @@ -# -*- 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 + +import FreeCAD ___DXFVersion___ = "1.4.0" try: - import __builtin__ as builtin #py2 + pass # py2 except: - import builtins as builtin #py3 + pass # py3 -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 +50,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 +66,24 @@ 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..c6e3df0 100644 --- a/commits_num.py +++ b/commits_num.py @@ -1,65 +1,67 @@ -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""" + 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..6914e87 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,203 @@ # 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 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') + 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: + 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 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 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()) + 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--') + 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: 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): + 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 + 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') + print(g, i) + FreeCAD.Console.PrintWarning("too short\n") idx_to_del.append(i) - if 'Circle' in str(g): + 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 "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 +212,129 @@ 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' + # 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__: + 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__ + ): 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 +342,69 @@ 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) + # sayw(old_sk_constraints) for oc in old_sk_constraints: sk_constraints.append(oc) - #say(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..2a55dd1 100644 --- a/exchangePositions.py +++ b/exchangePositions.py @@ -1,731 +1,878 @@ -# -*- 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: + if 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: + 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) 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: + 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) + + ### 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: + full_content = [] + positions_content = [] + sketch_content = [] + sketch_content_header = [] + # if doc is not None: if len(doc.FileName) == 0: - docFn = 'File Not Saved' + 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') + 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="" + 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): + # if os.path.exists(name): f = open(name, "w") - f.write(''.join(full_content)) + f.write("".join(full_content)) f.close + ## 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: + full_content = [] + positions_content = [] + sketch_content = [] + sketch_content_header = [] + # if doc is not None: if len(doc.FileName) == 0: - docFn = 'File Not Saved' + 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) + 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'): + 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) + 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) + 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="" + 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))) + 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) + 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])))) + 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): + 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 = open(home + r"\list_diff.lst", "w") + f.write("".join(diff_content)) f.close 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..a6d1f3d 100644 --- a/explode.py +++ b/explode.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'C:\Cad\Progetti_K\3D-FreeCad-tools\explode.ui' # @@ -9,58 +8,69 @@ __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: + if "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 +80,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 +190,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 +200,212 @@ 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(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 "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: - if hasattr (o, 'Shape'): - if (pos != 0): + elif "topSilk" in o.Label or "botSilk" in o.Label: + if 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) + ((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 +413,3 @@ def runExplodeGui(): # ui.setupUi(explode_dwg) # explode_dwg.show() # sys.exit(app.exec_()) - - diff --git a/fps.py b/fps.py index 0508a38..f63dd67 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') -current_milli_time = lambda: int(round(time.time() * 1000)) +FC_majorV, FC_minorV, FC_git_Nbr = getFCversion() +FreeCAD.Console.PrintWarning("FC Version " + str(FC_majorV) + str(FC_minorV) + "-" + str(FC_git_Nbr) + "\n") + + +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,100 @@ 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") + 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 +177,43 @@ 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 +225,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 +280,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 +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 +352,242 @@ 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") + + Filter = "" 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]) + pcb_col = assign_col[pcb_color_pos] if pcb_color_pos == 9: - slk_col = '#2d2d2d' + pass else: - slk_col = '#f8f8f0' - pads_color = (0.81,0.71,0.23) #(0.85,0.53,0.10) + pass + 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') + + tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".kicad_pcb") with tmp as f: - #with open(tmp.name, 'w') 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 +599,287 @@ 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 +888,38 @@ 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 +927,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..d62b7bf 100644 --- a/kicadStepUpCMD.py +++ b/kicadStepUpCMD.py @@ -1,132 +1,144 @@ -# -*- 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 +147,58 @@ 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 hasattr(ap, "Placement"): if len(ap.InListRecursive) < lvl: top = ap lvl = len(ap.InListRecursive) - #else: + # 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,282 +207,300 @@ 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 = 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]))) + 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 + ow = e.OuterWire + wires.append(ow) + # es = ow.Edges for _e in ow.Edges: cp_edges.append(_e) 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) @@ -484,14 +512,14 @@ def ksu_edges2sketch(): 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 +529,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 +597,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 +622,51 @@ 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 +677,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 +694,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 +706,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 +721,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 +743,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 +766,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 +800,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)) @@ -773,7 +812,11 @@ def setupUi(self, CDialog): self.coincident.setToolTip(translate("Ui_CDialog", "Lock Coincident")) self.coincident.setText("") icon1 = QtGui.QIcon() - icon1.addPixmap(QtGui.QPixmap("Sketcher_LockCoincident.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon1.addPixmap( + QtGui.QPixmap("Sketcher_LockCoincident.png"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.coincident.setIcon(icon1) self.coincident.setIconSize(QtCore.QSize(48, 48)) self.coincident.setChecked(False) @@ -818,40 +861,45 @@ 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 map(str, [self.tolerance.text(), self.all_constraints.isChecked(), self.rmvXGeo.isChecked()]) - + # 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 +907,88 @@ 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 +1001,132 @@ 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)) + 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 - sv0 = Draft.makeShape2DView(FreeCAD.ActiveDocument.getObject(sk.Name), FreeCAD.Vector(-0.0, -0.0, 1.0)) + # 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 +1134,70 @@ 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): + for j in range(n): mv.append(j) 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 +1205,478 @@ 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(',','.')) + reply = offsetDlg.exec_() + if reply == 1: # ok + offset = float(ui.lineEdit_offset.text().replace(",", ".")) if ui.checkBox.isChecked(): - offset_method = 'Arc' + offset_method = "Arc" else: - offset_method = 'Intersection' - doc.openTransaction('off2D') + offset_method = "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 +1686,114 @@ 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 +1801,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 + + # if a3: + if "LinkView" in dir(FreeCADGui): # pre a3 Link3 merge return True - else: - return False - + return False + 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 +1893,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 +1911,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 +1970,158 @@ 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: + # else: # return True - #import kicadStepUptools + # import kicadStepUptools return True - + 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: + # else: # return True - #import kicadStepUptools + # import kicadStepUptools return True - + 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 +2131,60 @@ 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,129 +2195,154 @@ 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' + if "True" in dv: + constr = "all" else: - constr = 'coincident' - if i ==2: - if 'True' in dv: + constr = "coincident" + if i == 2: + if "True" in dv: rmvXG = True else: rmvXG = False @@ -2098,96 +2350,122 @@ def Activated(self): 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 +2478,317 @@ 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 + sel = FreeCADGui.Selection.getSelection() + if len(sel) > 1 or len(sel) == 0: + return False + if len(sel) == 1: + if hasattr(sel[0], "TypeId"): + if (sel[0].TypeId) != "App::Part": + return False return True -FreeCADGui.addCommand('ksuToolsResetPartPlacement',ksuToolsResetPartPlacement()) + + +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 +2796,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 +2859,327 @@ 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 +3189,538 @@ 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 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 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 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") + ## - 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 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 + 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 True + 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") + + ### make_compound = False @@ -3242,69 +3730,71 @@ 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 + vis = True for Container in o.InListRecursive: if not (FreeCADGui.ActiveDocument.getObject(Container.Name).Visibility): - vis=False + vis = False if vis: copied_subobjects_Names.append(o.Name) - copied_subobjects += copy_subobject(doc, o,suffix) + 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) + pName = "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 +3808,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 +3831,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 +3859,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 +3871,53 @@ 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'): + if obj not in objs: + if frozenset(obj.InList) - totoggle: + if 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 +3926,49 @@ 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 +3982,125 @@ 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 +4108,48 @@ 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 +4157,1191 @@ 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): + if not o.ViewObject.Visibility: + if ( + 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") + 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: + sel = FreeCADGui.Selection.getSelection() + if len(sel) == 1: return True - #else: + 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: + 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 + from kicadStepUptools import ZoomFitThread, removesubtree, restore_specular, restore_specular_cls + 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=[] + # 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') + if 1: # using internal dxf old legacy library loader makefacedxf.checkDXFsettings(): + doc.openTransaction("add_silks") makefacedxf.makeFaceDXF() doc.commitTransaction() else: @@ -4585,394 +5350,467 @@ 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"): + if 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): + 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: if g.Radius == rads[i]: - found=True + 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()) -class approximateCenter(): +FreeCADGui.addCommand("Arcs2Circles", Arcs2Circles()) + + +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 +5823,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: + sel = FreeCADGui.Selection.getSelection() + if len(sel) >= 1: return True - return + 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 +5863,257 @@ 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: + if hasattr(o.ViewObject, "Visibility"): + if 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) + 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') + 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) + elif hasattr(o, "Mesh"): + sm = make_shape_from_mesh(doc, o) cmpd_objs.append(sm) toDel_objs.append(sm) - BBCompound.Links = cmpd_objs # sel + 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]): + 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 - + 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 +6131,38 @@ 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]): + # 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]) + sl[0] + # faceSel = ob.SubObjects[0] + norm, _plcm, _top, _bbC = getNormalPlacementHierarchy(sl[0]) cam = FreeCADGui.ActiveDocument.ActiveView.getCameraNode() - if inv_view==True: #: + if inv_view: #: # sayerr('double click: inversion View') - #dirz = faceSel.normalAt(0,0)*-1 - dirz = norm*-1 + # dirz = faceSel.normalAt(0,0)*-1 + dirz = norm * -1 else: # sayw('single click: standard View') - #dirz = faceSel.normalAt(0,0) + # 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)) + 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("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..510bbd9 100644 --- a/kicadStepUptools.py +++ b/kicadStepUptools.py @@ -1,72 +1,71 @@ #!/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 * -#* * -#**************************************************************************** +# **************************************************************************** +# * * +# * 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 @@ -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,82 @@ ## 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 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 +# import configparser #utf-8 +# from codecs import open #maui to verify -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 +514,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 +595,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 +610,7 @@ ;compound = disallowed ;compound = simplified """ -constraints_section=u""" +constraints_section = """ [sketch_constraints] constraints = all ;constraints = all @@ -628,22 +618,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 +642,125 @@ """ 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 +768,124 @@ 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) + if 'geometryModeFlags="00000000000000000000000000000010"' in geo.Content: + # print('geometryModeFlags', True) + return True + # print('geometryModeFlags', False) + return False + + PY3 = sys.version_info[0] == 3 # maui @realthunder fcad_pcb py3 if PY3: - string_types = str, + string_types = (str,) else: - string_types = basestring, + string_types = (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_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") 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 + 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 - + 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') + # use_Links=True #False + FreeCAD.Console.PrintWarning("Asm3 WB present\n") except: pass - #FreeCAD.Console.PrintWarning('Asm3 WB not 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 +899,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 +909,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 +919,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 +929,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 +938,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 +947,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 +956,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 +965,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 +974,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 +983,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 +992,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 +1001,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 +1010,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 +1019,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 +1028,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 +1037,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 +1046,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 +1055,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 +1064,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 +1073,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 +1082,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 +1091,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 +1100,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 +1109,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 +1118,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 +1127,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 +1136,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 +1145,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 +1154,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 +1163,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 +1181,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 +1190,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 +1208,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 +1216,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 +1230,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 +1238,248 @@ 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"]) +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 +1488,565 @@ 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"] + cv = [o for o in t.children() if o.objectName() == "Combo View"] if cv: cv = cv[0] else: cv = 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 + + importlib.reload(lib) -def open(filename,insert=None): - #reply = QtGui.QMessageBox.information(None,"info", filename) - #onLoadBoard_cmd(filename) + +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") + 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 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: + + +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)) + # 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 +2057,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 +2070,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 +2093,162 @@ 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 = tempfile.TemporaryFile(dir=path) testfile.close() - #sayw('ok') + # 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 + # 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 = 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' + filename = path + os.sep + exp_name + ".wrz" else: - filename=path+os.sep+exp_name+'.wrl' + filename = 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; + applyDiffuse = 1 for color in single_color: color_vector.append(color) - #say("color_vector") - #say(color_vector) + # 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]) - meshes.append(shapeToMesh(singleFace, color_vector[indexColor], transparency[i], mesh_dev, scale)) + if applyDiffuse: + # say(color_vector[indexColor]) + meshes.append( + shapeToMesh( + singleFace, + color_vector[indexColor], + transparency[i], + mesh_dev, + scale, + ) + ) else: - #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 + # 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 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 +3208,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 +3248,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 +3331,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 +3342,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 +3389,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 +3403,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 +3444,519 @@ 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 + # print(min_drill_size) + if prefs.GetBool("vrml_materials"): + enable_materials = 1 else: - enable_materials=0 - if prefs.GetBool('mode_virtual'): - addVirtual=1 + 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' + 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 + links_imp_mode = "links_not_allowed" + if prefs.GetBool("asm3_linkGroups"): + pass 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') + pass + 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 +3964,342 @@ 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"): + if 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 +4307,349 @@ 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' + cpmode = "compound" else: - cpmode='part' - suffix='_' - to_export_name=kicadStepUpCMD.deep_copy(doc,cpmode,suffix) + cpmode = "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" + 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 - + fpath = 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 +4657,422 @@ 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')): + 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, "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 +5082,484 @@ 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 != '': + 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 + 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] + 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 + 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 + 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 = '' + myModelNbr = "" else: - myModelNbr = '['+str(myModelNbr)+']' - if '*' not in myReference: - newStep.Label = myReference + '_'+ impLabel + '_' + myTimeStamp + myModelNbr + myModelNbr = "[" + 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 + 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: + md_hide = False + + # 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 +5568,160 @@ 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 + 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 = '' + 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 + 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 + ) # 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 +5729,1027 @@ 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 == '': + if ROT == "": ROT = 0.0 else: ROT = float(ROT) - #say('module pos & rot '+str(X1)+' '+str(Y1)+' '+str(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 == '': + if ROT == "": ROT = 0.0 else: ROT = float(ROT) - #say('module pos & rot '+str(X1)+' '+str(Y1)+' '+str(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 + txtFile = codecs.open(filename, mode="rb", encoding="utf-8", errors="replace", buffering=1) # 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)) + 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)) 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 + 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 + + ### 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) + # say("rotate vrml: "+rotz) else: - rotz_vrml_m="(xyz 0 0 0" - if rotz=='': - rotz=0.0 + rotz_vrml_m = "(xyz 0 0 0" + if rotz == "": + rotz = 0.0 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 = 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 +6759,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 +6775,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 +6784,32 @@ 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: + Filter = "" ##if _platform == "darwin": ## ##workaround for OSX not opening native fileopen ## name=QtGui.QFileDialog.getOpenFileName(self, 'Open file', @@ -6151,208 +6818,222 @@ 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: + # 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: + # 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() + # zf= Timer (0.3,ZoomFitThread) + # zf.start() if disable_VBO: if VBO_status: - paramGetV.SetBool("UseVBO",True) + paramGetV.SetBool("UseVBO", True) sayw("enabling VBO") if disable_PoM_Observer: if PoMObs_status: Observer.start() - # paramGetPoM.SetBool("EnableObserver",True) + # paramGetPoM.SetBool("EnableObserver",True) sayw("enabling PoM Observer") - #txtFile.close() + # 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" + # 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='' + 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 + 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 + 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') + print(g, i) + sayw("too short") idx_to_del.append(i) - if 'Circle' in str(g): + 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 "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 +7041,92 @@ 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' + # 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__: + tp = "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 +7134,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 +7202,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 +7237,128 @@ 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: - 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') + # 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 +7369,397 @@ 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: + 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]: # # 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) + if hasattr(mypcb, "general"): + pcbThickness = float(mypcb.general.thickness) else: - pcbThickness=1.6 + pcbThickness = 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 +7770,364 @@ 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) + pcb_sk = FreeCAD.ActiveDocument.getObject(newname) gi = 0 for g in pcb_sk.Geometry: - if 'BSplineCurve object' in str(g): + 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),'',[]) + gi += 1 + 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')]) + 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 - elif override_pcb == True: - if doc.getObject(sketch_name_sfx) in doc.Objects: #if 1: #try: + docG.getObject(sketch_name_sfx).Visibility = True + elif override_pcb: + if doc.getObject(sketch_name_sfx) in doc.Objects: # if 1: #try: docG = FreeCADGui.ActiveDocument - docG.getObject(sketch_name_sfx).Visibility=True + 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 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 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) + paramGetV.SetBool("UseVBO", True) sayw("enabling VBO") if disable_PoM_Observer: if PoMObs_status: Observer.start() - # paramGetPoM.SetBool("EnableObserver",True) + # 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 +8138,91 @@ 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: + 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 "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'): + 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_() + reply = StepPrefsDlg.exec_() sayw(msg) - #QtGui.QApplication.restoreOverrideCursor() - #reply = QtGui.QMessageBox.information(None,"Info ...",msg) - else: #first time new settings parameter + # 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_() + 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 +8237,1008 @@ 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') + 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") + # 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') + 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") + # 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=[] + + 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") + # 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') + 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") + # 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") + # 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() + 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") + # 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') + 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") + # 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 !")) + 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() + # 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, + # diag = QtGui.QMessageBox(QtGui.QMessageBox.Icon.Critical, # msg1, # msg) - #diag.setWindowModality(QtCore.Qt.ApplicationModal) - #diag.exec_() + # 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') + 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") + # 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) + # 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"): + 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: + 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 +9257,77 @@ 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 +9335,355 @@ 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") - + + ### ############################# 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): - #sa = atan2 (ys-cy, xs-cx) - #ea = atan2 (ye-cy, xe-cx) + +def arcAngles2(edge, angle): # (xs, ys, xe, ye, cx, cy, angle): + + # 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 +9695,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 +9726,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 +9748,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 +9757,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 +9781,29 @@ def getCircle(layer, content, oType): radius = sqrt((xs - x1) ** 2 + (ys - y1) ** 2) - if i[5] == '': + if i[5] == "": width = 0.01 else: width = 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,7 +9812,7 @@ def getCircleF(layer, content, oType, m=[0,0]): radius = sqrt((xs - x1) ** 2 + (ys - y1) ** 2) - if i[5] == '': + if i[5] == "": width = 0.01 else: width = float(i[5]) @@ -8833,8 +9823,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 +9836,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 +9844,44 @@ 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() != '': + if i[6].strip() != "": width = float(i[6]) else: width = 0 - if abs(curve)==360: + 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,28 +9889,31 @@ def getArc(layer, content, oType): ym = float(i[3]) x1 = float(i[4]) y1 = float(i[5]) - if i[6].strip() != '': + if i[6].strip() != "": width = float(i[6]) else: width = 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() != '': + if i[6].strip() != "": width = float(i[6]) else: width = 0 @@ -8922,82 +9928,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 +10013,126 @@ def getwrlData(source): # #say("rotz temp:"+temp[2]) # ##rotz=temp[2] # #say("rotate vrml: "+rotz) - if zrot_vrml=='': - zrot_vrml=0.0 + 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 = 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 + 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 = float(rotz) + return rotz # adding vrml module z-rotation + ### 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 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 + 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 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 +10140,122 @@ 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() == '': + if not data_off[0] or data_off[0].strip() == "": xOF = 0.0 else: xOF = float(data_off[0]) - if not data_off[1] or data_off[1].strip() == '': + if not data_off[1] or data_off[1].strip() == "": yOF = 0.0 else: yOF = 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() == '': + if not data[4] or data[4].strip() == "": xOF = 0.0 else: xOF = float(data[4]) - if not data[5] or data[5].strip() == '': + if not data[5] or data[5].strip() == "": yOF = 0.0 else: yOF = 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 +10264,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 +10305,40 @@ 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': - 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))) + 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 +10352,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 +10390,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 +10418,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 +10442,54 @@ 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': - 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))) + 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))) 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 +10503,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 +10544,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 +10579,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 @@ -9518,72 +10628,90 @@ def createLine(x1, y1, x2, y2, width=0.01): 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 perc > 100.0: + perc == 100.0 if dx > dy: - e = dy * perc / 100. + e = dy * perc / 100.0 else: - e = dx * perc / 100. + e = 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 +10720,90 @@ 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))) + 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))) + 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))) + 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))) + 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 +10812,20 @@ 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 perc > 100.0: + perc == 100.0 if dx > dy: - e = dy * perc / 100. + e = dy * perc / 100.0 else: - e = dx * perc / 100. + e = dx * perc / 100.0 else: # mm e = perc p1 = [x - dx + e, y - dy, z_off] @@ -9664,197 +10836,248 @@ 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))) + 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))) + 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))) + 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))) + 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 + z_offset = 0 + 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": + 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) + 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) 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 +11086,159 @@ 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): ##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 +11247,510 @@ 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)) + 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)) if FreeCAD.activeDocument(): - doc=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\'') + doc = 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 +11759,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 +11844,506 @@ 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 +12351,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 +12373,423 @@ 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,140 +12797,126 @@ 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): - def makefeatures(self,doc): - import FreeCAD def addshape(faceindex): - obj=doc.addObject('Part::Feature','facefromedges_%d' % faceindex) + obj = doc.addObject("Part::Feature", "facefromedges_%d" % 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", "facesfromedges_%d" % 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 - + 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 + 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 - - 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))] + 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: @@ -11638,103 +12925,113 @@ def median(v1,v2): else: prev = None else: - prev = debuglist[i-1] - #print "prev=",prev - if i == (len(debuglist)-1): + 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] + nexte = 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) 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): 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) + # print (mypcb.general) #maui errorchecking + if hasattr(mypcb, "general"): + totalHeight = float(mypcb.general.thickness) else: - totalHeight=1.6 + totalHeight = 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 +13295,877 @@ 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 + 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.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 + if hasattr(ar, "layer"): + k_test = ar.layer else: - k_test=ar.layers + k_test = 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 + # print(lp) + # print(lp.layer) + # print(lp.pts) + if hasattr(lp, "layer"): + k_test = lp.layer else: - k_test=lp.layers + k_test = 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 + if hasattr(bs, "layer"): + k_test = bs.layer else: - k_test=bs.layers + k_test = 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 + if hasattr(r, "layer"): + k_test = r.layer else: - k_test=r.layers + k_test = 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"): + if 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 + + 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 + k_test = 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 + 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 + k_test = 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 + elif not hasattr(zn, "keepout"): + continue ind = 0 l = len(zn.polygon.pts.xy) z_lines = [] for p in 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 + 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 != "": + if 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 + for lp in mypcb.gr_poly: # pcb polylines + if hasattr(lp, "layer"): + k_test = lp.layer else: - k_test=lp.layers + k_test = 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 + if hasattr(bs, "layer"): + k_test = bs.layer else: - k_test=bs.layers + k_test = 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 +14173,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 +14187,101 @@ 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 + if hasattr(a, "layer"): + k_test = a.layer else: - k_test=a.layers + k_test = 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 + if hasattr(c, "layer"): + k_test = c.layer else: - k_test=c.layers + k_test = 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 +14291,249 @@ 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 + 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 = 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: + 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') - 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 +14544,84 @@ 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 +14630,181 @@ 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 +14812,101 @@ 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 +14916,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 +14970,253 @@ 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 +15227,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 +15332,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 +15410,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 +15451,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 +15459,441 @@ 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=[] + faces = [] for f in pcb_board.Shape.Faces: - faces.append(f) + faces.append(f) 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"): + if 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 +15902,7 @@ def addObject(shape,name="Shape",layer=None): # else: # pass # -#singleInstance() +# singleInstance() ############################################################################################################### @@ -14123,15 +15911,17 @@ 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)) + # QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr)) try: - QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr)) #workaround Qt5 waiting for PySide + QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr)) # workaround Qt5 waiting for PySide except: - #QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr.fromLocalFile())) + # QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr.fromLocalFile())) pass -#class Ui_DockWidget(object): + + # class Ui_DockWidget(object): def setupUi(self, DockWidget): DockWidget.setObjectName("DockWidget") DockWidget.resize(169, 480) @@ -14139,8 +15929,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,17 +15942,21 @@ 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) + icon1.addPixmap( + QtGui.QPixmap("icons-new/dock_left.png"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.dock_left.setIcon(icon1) self.dock_left.setIconSize(QtCore.QSize(24, 24)) self.dock_left.setObjectName("dock_left") 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 +15966,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,17 +15976,21 @@ 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) + icon4.addPixmap( + QtGui.QPixmap("icons-new/dock_right.png"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.dock_right.setIcon(icon4) self.dock_right.setIconSize(QtCore.QSize(24, 24)) self.dock_right.setObjectName("dock_right") 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 +16035,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 +16045,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 +16055,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 +16065,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 +16075,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 +16085,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 +16124,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 +16134,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 +16144,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 +16154,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 +16164,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 +16174,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 +16191,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 +16201,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,17 +16211,21 @@ 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) + icon20.addPixmap( + QtGui.QPixmap("icons-new/Sketcher_Rectangle.png"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.pushPCB.setIcon(icon20) self.pushPCB.setObjectName("pushPCB") self.gridLayout_8.addWidget(self.pushPCB, 3, 3, 1, 1) 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,20 +16235,28 @@ 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) + icon22.addPixmap( + QtGui.QPixmap("icons-new/importBoard.png"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.LoadBoard.setIcon(icon22) self.LoadBoard.setObjectName("LoadBoard") self.gridLayout_8.addWidget(self.LoadBoard, 2, 0, 1, 1) 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) + icon23.addPixmap( + QtGui.QPixmap("icons-new/export3DModel.png"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.ScaleVRML.setIcon(icon23) self.ScaleVRML.setObjectName("ScaleVRML") self.gridLayout_8.addWidget(self.ScaleVRML, 1, 0, 1, 1) @@ -14464,14 +16274,18 @@ def setupUi(self, DockWidget): self.cb_materials.setMaximumSize(QtCore.QSize(64, 128)) self.cb_materials.setText("") icon25 = QtGui.QIcon() - icon25.addPixmap(QtGui.QPixmap("icons-new/materials.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon25.addPixmap( + QtGui.QPixmap("icons-new/materials.png"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.cb_materials.setIcon(icon25) self.cb_materials.setObjectName("cb_materials") self.gridLayout_8.addWidget(self.cb_materials, 1, 1, 1, 1) 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) @@ -14483,14 +16297,18 @@ def setupUi(self, DockWidget): self.cb_expStep.setMaximumSize(QtCore.QSize(128, 64)) self.cb_expStep.setText("") icon27 = QtGui.QIcon() - icon27.addPixmap(QtGui.QPixmap("icons-new/exportPart.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + icon27.addPixmap( + QtGui.QPixmap("icons-new/exportPart.png"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.cb_expStep.setIcon(icon27) self.cb_expStep.setObjectName("cb_expStep") self.gridLayout_8.addWidget(self.cb_expStep, 2, 3, 1, 1) 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,37 +16318,49 @@ 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) + icon29.addPixmap( + QtGui.QPixmap("icons-new/add_block.png"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.import3D.setIcon(icon29) self.import3D.setObjectName("import3D") self.gridLayout_8.addWidget(self.import3D, 0, 1, 1, 1) 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) + icon30.addPixmap( + QtGui.QPixmap("icons-new/collisions.png"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.checkCollisions.setIcon(icon30) self.checkCollisions.setObjectName("checkCollisions") self.gridLayout_8.addWidget(self.checkCollisions, 3, 1, 1, 1) 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) + icon31.addPixmap( + QtGui.QPixmap("icons-new/export3DStep.png"), + QtGui.QIcon.Normal, + QtGui.QIcon.Off, + ) self.export3DStep.setIcon(icon31) self.export3DStep.setObjectName("export3DStep") self.gridLayout_8.addWidget(self.export3DStep, 3, 0, 1, 1) 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 +16376,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 +16581,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 +16624,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 +16658,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 +17087,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") @@ -15278,72 +17124,70 @@ 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 +17197,432 @@ 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="" + # 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' + if prefs_.GetBool("stpz_export_enabled"): + ext_ = ".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") + 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' + cpmode = "compound" else: - cpmode='part' - suffix='_' - to_export_name=kicadStepUpCMD.deep_copy(doc,cpmode,suffix) + cpmode = "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="" + 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 +17641,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 +17667,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 +17678,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 +17689,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 +17703,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 +17727,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 +17757,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 +17768,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 +17787,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 +17802,40 @@ 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: - msg = translate("PushPCB", "Edge editing NOT supported on FC0.15!
    please upgrade your FC release") + # 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 +17844,130 @@ 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="" + 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 +17976,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 +17994,95 @@ 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="" + 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 + 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 if fname is None: - fpath=original_filename + fpath = original_filename else: - fpath=fname - sayerr('Loading from '+fpath) - #stop + fpath = 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 +18092,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 +18231,413 @@ 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="" + 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 + 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 if fname is None: - fpath=original_filename + 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] + 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 + 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 + m_angle = 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 +18647,249 @@ 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="" + 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 + 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 if fname is None: - fpath=original_filename + fpath = original_filename else: - fpath=fname - sayerr('loading from '+fpath) - #stop + fpath = 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 + if hasattr(mypcb, "setup"): + if hasattr(mypcb.setup, "grid_origin"): + oft = mypcb.setup.grid_origin else: - oft = [0.0,0.0] + oft = [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 +18898,223 @@ 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"): + 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 "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') + # print(o.Label,'sk added') sk_to_convert.append(o) - to_discretize=False - if 'Pads_Poly' in o.Label: - if hasattr(o,"Geometry"): + 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 "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') + # 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) # 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 +19137,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 +19179,292 @@ 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="" + 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.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=[] + # 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) 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 +19504,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 +19528,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 +19561,53 @@ 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) 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 +19615,620 @@ 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 = "fc_footprint" + if flabel == "" or flabel is None: fp_name = FreeCAD.ActiveDocument.Name else: fp_name = flabel - #print(fp_name, 'fp_name1') - + # 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.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=[] + # 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) + # 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' + edge_thick = 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) + 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' + edge_thick = 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) + 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' + edge_thick = 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) + 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' + edge_thick = 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) + 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' + edge_thick = 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) + 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' + edge_thick = 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) + 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) + edge_thick = 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 +20247,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 +20272,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 +20429,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 +20459,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 +20535,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 +20748,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 +21223,572 @@ 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 + 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" + if tp == "TH": + ptp = "thru_hole" 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('_','')+'"' + 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("_", "") + + '"' + ) 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' + 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) + 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 " + + 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 +21807,88 @@ 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 +21920,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 +21996,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 +22120,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 +22334,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 +22624,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 +22676,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 +22822,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 +22888,112 @@ 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("%s (degree : %d / nb poles : %d)" % (bc, bc.Degree, 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 +23003,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 +23065,307 @@ 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' + # 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 + if "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' + layer = "Edge.Cuts" else: layer = sklayer - if edg[0] == 'line': + 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 +23376,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 +23386,222 @@ 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'): + if hasattr(s, "GeometryFacadeList"): Gm = s.GeometryFacadeList else: Gm = s.Geometry - #if hasattr(Gm[i],'Construction'): + # 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'): + if hasattr(s, "GeometryFacadeList"): Gm = s.GeometryFacadeList else: Gm = s.Geometry - #if hasattr(Gm[i],'Construction'): + # 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'): + # print(type(j.Geometry[k]).__name__) + if hasattr(j, "GeometryFacadeList"): Gm = j.GeometryFacadeList else: Gm = j.Geometry - #if hasattr(Gm[k],'Construction'): + # 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 +23609,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 +23643,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 +23674,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 +23687,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 +23728,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 +23814,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 +23860,286 @@ 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 + + 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 + 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] + 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": + 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: # 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 +24151,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 +24213,234 @@ 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 +24453,694 @@ 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() + r'"*\))', + data, + re.MULTILINE | re.DOTALL, + ) + ) + > 0 + or len( + re.findall( + r"\s*\(uuid(\s.*" + tsp.upper() + r'"*\))', + 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: + 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 - + 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: + 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 = 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) + 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))) + mod_old_angle = float(f"{float(mod_old_angle):.3f}") 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))+\ + # 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 + 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 = 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 +25152,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 +25183,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 +25235,84 @@ 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"] + 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': + # 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 +25320,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..781b300 100644 --- a/kicad_parser.py +++ b/kicad_parser.py @@ -1,60 +1,71 @@ #!/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, + string_types = (str,) else: - string_types = basestring, + string_types = (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 +77,106 @@ 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) + 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) + 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 +190,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 +348,52 @@ 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 +407,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,10 +493,10 @@ 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: @@ -462,103 +505,108 @@ def getFaceCompound(shape,wire=False): for w in f.Wires: objs.append(w) 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)) + logger.exception(f"failed to load model: {ex}") 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 +619,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 +636,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 +675,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 +721,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 +742,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 +753,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 +802,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 +832,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 +861,13 @@ 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 +879,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 +896,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 +905,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 +932,102 @@ 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' + def _log(self, msg, *arg, **kargs): + level = "info" if kargs: - if 'level' in kargs: - level = kargs['level'] + if "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 +1037,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,23 +1046,21 @@ 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): + for obj in objs if isinstance(objs, (list, tuple)) else (objs,): + if isinstance(obj, Part.Shape): shape = obj else: shape = obj.Shape @@ -1010,55 +1068,49 @@ def addRadiusConstraint(edge): 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 +1123,43 @@ 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 +1167,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 +1196,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 +1234,99 @@ 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=[] + to_del = [] for o in objn: to_del.append(o) - #to_del.append(ret) + # 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 +1335,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 +1356,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 +1369,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 +1387,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 +1405,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,43 +1425,43 @@ 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 @@ -1411,51 +1477,58 @@ def _makeShape(self, sexp, ctx, wires, non_closed=None, layer=None, at=None): 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 + 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 +1538,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 +1581,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 _face(obj,name): - return _wire(obj,name,True) + def _wire(obj, name, fill=False): + return self._makeWires(obj, name, fill=fill, label=width) - def _solid(obj,name): - return self._makeWires(obj,name,fill=True,label=width,fit_arcs=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) 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 +1732,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,27 +1771,27 @@ 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 @@ -1721,34 +1799,43 @@ def _solid(obj,name): thickness = 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 +1844,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 +1853,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 +1873,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 +1886,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 +1894,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 +1919,142 @@ 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 +2120,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 +2225,171 @@ 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'): + 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) + 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'): + pln = Part.Wire(make_gr_poly(pl)) + ws.append(pln) + if hasattr(pl, "stroke"): width = pl.stroke.width else: width = 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 +2397,205 @@ 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') + self._log("Unknown track type: {}", tp, level="warning") if self.merge_tracks: - label = '{}'.format(width) + label = f"{width}" else: - label = '{}#{}'.format(width,name) - objs.append(func(edges,label=label)) + label = 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 +2606,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 +2624,70 @@ 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: @@ -2895,41 +3070,42 @@ def make(self,copper_thickness=0.05,fit_arcs=True,load_parts=False, try: self.layer = None if combo > 1: - objs = self._makeFuse(objs,'pcb') + objs = self._makeFuse(objs, "pcb") else: - objs = self._makeCompound(objs,'pcb') + objs = 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 +3116,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/selection2edges.py b/selection2edges.py index df51c25..4dc798f 100644 --- a/selection2edges.py +++ b/selection2edges.py @@ -1,94 +1,134 @@ 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..ffd5dce 100644 --- a/step_amend.py +++ b/step_amend.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # **************************************************************************** # * Copyright (c) 2018 Maurice * # * * @@ -14,99 +13,105 @@ # 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..27d8953 100644 --- a/test-mb.py +++ b/test-mb.py @@ -1,5 +1,4 @@ - -from PySide import QtGui, QtCore +from PySide import QtCore # msg_box = QtGui.QMessageBox() # msg_box.setWindowTitle("Warning") @@ -9,159 +8,164 @@ # #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.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..6c2c44c 100644 --- a/tracks.py +++ b/tracks.py @@ -1,84 +1,99 @@ #!/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_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") 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 + 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 +101,88 @@ 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") + 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 +190,53 @@ 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 +247,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,185 +305,208 @@ 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") # 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") + Filter = "" 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]) + 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' + pass else: - slk_col = '#f8f8f0' + pass # 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 # (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='') + # 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: 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) + 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 @@ -455,56 +516,55 @@ def addtracks(fname = 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 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: if objsNum < len(FreeCAD.ActiveDocument.Objects): - tracks_=FreeCAD.ActiveDocument.ActiveObject + 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)) + # 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) + extrude_holes(holesSk, pcbThickness * 3) holes_ = FreeCAD.ActiveDocument.ActiveObject - cut_fuzzy(tracks_,holes_,0.00006) #6e-5 fuzzy tolerance + 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]) + 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) + 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_]) + add_toberemoved.append([tracks, tracks_]) topTracks = new_obj - #stop - + # stop + if 0: - ply_area=[] - for lp in mypcb.gr_poly: #pcb area polylines - if hasattr(lp, 'layer'): - k_test=lp.layer + 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: + k_test = 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) @@ -512,230 +572,274 @@ def addtracks(fname = None): 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) + ind += 1 + + 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 + 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'): + 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 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 + 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: + k_test = 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 + + 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: + k_test = 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 @@ -743,15 +847,14 @@ def addtracks(fname = 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='') + # 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: 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) + 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 @@ -760,144 +863,153 @@ def addtracks(fname = None): 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 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: if objsNum < len(FreeCAD.ActiveDocument.Objects): - tracksB_=FreeCAD.ActiveDocument.ActiveObject + tracksB_ = FreeCAD.ActiveDocument.ActiveObject objsNum = len(FreeCAD.ActiveDocument.Objects) - holesB=pcb.makeHoles(oval=True) + 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) + extrude_holes(holesSkB, pcbThickness * 3) holesB_ = FreeCAD.ActiveDocument.ActiveObject - cut_fuzzy(tracksB_,holesB_,0.00006) #6e-5 fuzzy tolerance + 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]) + 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) + 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_]) + add_toberemoved.append([tracksB, tracksB_]) botTracks = new_obj - #stop + # 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..b4d6344 100644 --- a/utf8test.py +++ b/utf8test.py @@ -1,100 +1,76 @@ #!/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") + return + 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") From c5307c6b8fbef620cd8174a60d297958823c5855 Mon Sep 17 00:00:00 2001 From: vlordier Date: Fri, 1 May 2026 01:48:11 +0200 Subject: [PATCH 3/3] fix: manual semantic fixes (SIM103, SIM115, PERF402, Copilot comments, etc.) Manual fixes across 19 files: - SIM103: inline boolean returns (kicadStepUpCMD, kicadStepUptools) - SIM115: with statements for file handles (exchangePositions, fps, kicadStepUptools, kicad_parser) - SIM113: enumerate() replaces manual counters (kicadStepUptools, tracks) - PERF402: .extend() replaces manual list copy loops (constrainator, kicadStepUpCMD, kicadStepUptools, kicad_parser) - UP031: printf-style to f-strings (kicadStepUptools) - RUF003: unicode chars in comments (kicadStepUptools, tracks) - YTT201: sys.version_info == 3 -> >= 3 (kicadStepUptools, kicad_parser) - TRY: logger.exception redundant exception arg (kicad_parser) - Copilot review fixes: import FreeCAD (Init.py), translate fallback (TranslateUtils.py), import scope (commits_num.py, ZipStepImport.py, _DXF_Import.py), dead expression (explode.py), dead Py2 code (utf8test.py), except block (makefacedxf.py) --- .git-blame-ignore-revs | 2 +- Init.py | 2 + InitGui.py | 42 +- TranslateUtils.py | 5 +- ZipStepImport.py | 7 +- _DXF_Import.py | 8 +- commits_num.py | 2 + constrainator.py | 162 ++- exchangePositions.py | 217 ++-- explode.py | 23 +- fps.py | 54 +- kicadStepUpCMD.py | 824 +++++++------- kicadStepUptools.py | 2354 +++++++++++++--------------------------- kicad_parser.py | 247 +---- selection2edges.py | 6 +- step_amend.py | 13 +- test-mb.py | 16 +- tracks.py | 292 +++-- utf8test.py | 1 - 19 files changed, 1521 insertions(+), 2756 deletions(-) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index f670b88..62e0fee 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,4 +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. -fa87e852980125a86d918ebaea65f0576c92455f +7cb8760cc1e5be808f61bbffcd8bb239e609352d diff --git a/Init.py b/Init.py index 3547f25..4eaa234 100644 --- a/Init.py +++ b/Init.py @@ -9,6 +9,8 @@ # * 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") # ___ver___ = "6.0.4.5" diff --git a/InitGui.py b/InitGui.py index a1905e5..e617fb6 100644 --- a/InitGui.py +++ b/InitGui.py @@ -42,6 +42,7 @@ global main_ksu_Icon main_ksu_Icon = os.path.join(ksuWB_icons_path, "kicad-StepUp-tools-WB.svg") + from PySide import QtGui import hlp @@ -66,7 +67,6 @@ class kSU_MainPrefPage: def selectDirectory(self): - selected_directory = QtGui.QFileDialog.getExistingDirectory() # Use the selected directory... print("selected_directory:", selected_directory) @@ -161,7 +161,6 @@ def GetClassName(self): return "Gui::PythonWorkbench" def Initialize(self): - global pref_page pref_page = True # False #True # import FreeCADGui @@ -381,7 +380,7 @@ def Activated(self):
    set \'checkUpdates\' to \'False\' to avoid this checking
    in \"Tools\", \"Edit Parameters\",
    \"Preferences\"->\"Mod\"->\"kicadStepUp\" """ - QtGui.QApplication.restoreOverrideCursor() + QtGui.QApplication.restoreOverrideCursor() # noqa: F823 QtGui.QMessageBox.information(None, "Warning", msg) else: upd = pg.GetBool("checkUpdates") @@ -392,11 +391,17 @@ def mk_str(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 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") @@ -467,30 +472,25 @@ def find_nm(n): 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 = "" # 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 + 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("/")), - ) + prefs.SetString("prefix3d_2", mk_str(models3D_prefix2.replace("\\", "/").rstrip("/"))) # stop ## FreeCAD.Console.PrintError("new 'preferences Page' added to configure StepUp!!!\n") diff --git a/TranslateUtils.py b/TranslateUtils.py index 1455414..de4fc28 100644 --- a/TranslateUtils.py +++ b/TranslateUtils.py @@ -1,4 +1,3 @@ - # *************************************************************************** # * * # * Copyright (c) 2017 Yorik van Havre * @@ -35,4 +34,6 @@ def QT_TRANSLATE_NOOP(ctx, txt): if hasattr(FreeCAD, "Qt"): translate = FreeCAD.Qt.translate else: - pass + + def translate(_context, text): + return text diff --git a/ZipStepImport.py b/ZipStepImport.py index 602f1a1..71f8a88 100644 --- a/ZipStepImport.py +++ b/ZipStepImport.py @@ -32,12 +32,9 @@ import FreeCAD -___ZipVersion___ = "1.0.5" +from TranslateUtils import translate -try: - pass # py2 -except: - pass # py3 +___ZipVersion___ = "1.0.5" if open.__module__ in ["__builtin__", "io"]: diff --git a/_DXF_Import.py b/_DXF_Import.py index 1497efa..156b241 100644 --- a/_DXF_Import.py +++ b/_DXF_Import.py @@ -30,12 +30,9 @@ import FreeCAD -___DXFVersion___ = "1.4.0" +from TranslateUtils import translate -try: - pass # py2 -except: - pass # py3 +___DXFVersion___ = "1.4.0" if open.__module__ in ["__builtin__", "io"]: @@ -83,6 +80,7 @@ def read(filename): from dxf_parser import _importDXF global _dxfLibrary, _dxfColorMap, _dxfReader + from dxf_parser import _dxfColorMap, _dxfLibrary, _dxfReader # _importDXF.processdxf(FreeCAD.ActiveDocument, filename, getShapes=True, reComputeFlag=True) diff --git a/commits_num.py b/commits_num.py index c6e3df0..02ef7a7 100644 --- a/commits_num.py +++ b/commits_num.py @@ -51,6 +51,8 @@ def commitCount(u, r): def latestCommitInfo(u, r): """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() diff --git a/constrainator.py b/constrainator.py index 6914e87..9632da7 100644 --- a/constrainator.py +++ b/constrainator.py @@ -22,8 +22,6 @@ def sk_distance(p0, p1): 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) @@ -39,80 +37,79 @@ def sanitizeSkBsp(s_name, dist_tolerance): 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 "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: - 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]))) + 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) - # 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]))) + 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) - # 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) + eqp = False + break # break the for loop + # print('next--') + if eqp: + idx_to_del.append(j) j += 1 j = 0 # print(idx_to_del) @@ -157,11 +154,10 @@ def sanitizeSk(s_name, 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") - idx_to_del.append(i) + 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 @@ -191,7 +187,7 @@ def add_constraints(s_name, edge_tolerance, add_Constraints): FreeCAD.Console.PrintMessage("Constrainator version " + __ksuConstrainator_version__ + "\n") FreeCAD.Console.PrintMessage( - "adding " + add_Constraints + " constraints with " + str(edge_tolerance) + "mm tolerance\n" + "adding " + add_Constraints + " constraints with " + str(edge_tolerance) + "mm tolerance\n", ) if hasattr(Part, "LineSegment"): g_geom_points = { @@ -244,10 +240,7 @@ def add_constraints(s_name, edge_tolerance, add_Constraints): # 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" + 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__ @@ -398,8 +391,7 @@ def add_constraints(s_name, edge_tolerance, add_Constraints): s.Constraints = [] # sayw(old_sk_constraints) - for oc in old_sk_constraints: - sk_constraints.append(oc) + sk_constraints.extend(old_sk_constraints) # say(sk_constraints) s.addConstraint(sk_constraints) FreeCAD.ActiveDocument.recompute() diff --git a/exchangePositions.py b/exchangePositions.py index 2a55dd1..f908af0 100644 --- a/exchangePositions.py +++ b/exchangePositions.py @@ -1,4 +1,3 @@ - ## 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 @@ -127,9 +126,8 @@ def gui_addSelection(obj): def decimals(f, n): v = str(round(f, n)) - if "." in v: - if len(v[v.find(".") :]) > n + 1: - v = v[: len(v) - 1] + if "." in v and (len(v[v.find(".") :]) > n + 1): + v = v[: len(v) - 1] return float(v) @@ -157,11 +155,10 @@ def roundMatrix(mtx): 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) + 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) @@ -216,11 +213,10 @@ def roundVal(v, n_dec=None): 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) + 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) @@ -270,10 +266,7 @@ def expPos(doc=None): ## export positions sketch_content = [] sketch_content_header = [] # if doc is not None: - if len(doc.FileName) == 0: - docFn = "File Not Saved" - else: - docFn = doc.FileName + docFn = "File Not Saved" if len(doc.FileName) == 0 else doc.FileName line = "title: " + doc.Name full_content.append(line + "\n") line = "FileN: " + docFn @@ -288,7 +281,9 @@ def expPos(doc=None): ## export positions 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 not in {"App::Line", "App::Plane"} + (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]) @@ -389,11 +384,10 @@ def expPos(doc=None): ## export positions 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( + name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName( None, "Write 3D models & footprint positions to a Report file ...", home, @@ -420,9 +414,8 @@ def expPos(doc=None): ## export positions # say(name) if name: # if os.path.exists(name): - f = open(name, "w") - f.write("".join(full_content)) - f.close + with open(name, "w") as f: + f.write("".join(full_content)) ## @@ -435,10 +428,7 @@ def cmpPos(doc=None): ## compare exported positions with the selected doc sketch_content = [] sketch_content_header = [] # if doc is not None: - if len(doc.FileName) == 0: - docFn = "File Not Saved" - else: - docFn = doc.FileName + docFn = "File Not Saved" if len(doc.FileName) == 0 else doc.FileName line = "title: " + doc.Name full_content.append(line + "\n") line = "FileN: " + docFn @@ -453,7 +443,9 @@ def cmpPos(doc=None): ## compare exported positions with the selected doc 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 not in {"App::Line", "App::Plane"} + (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)+\ @@ -474,22 +466,21 @@ def cmpPos(doc=None): ## compare exported positions with the selected doc 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 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) @@ -529,11 +520,9 @@ def cmpPos(doc=None): ## compare exported positions with the selected doc # 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( + name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( None, "Open 3D models & footprint positions Report file\nto compare positions with the Active Document...", home, @@ -592,13 +581,9 @@ def cmpPos(doc=None): ## compare exported positions with the selected doc 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(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", "") @@ -621,7 +606,7 @@ def cmpPos(doc=None): ## compare exported positions with the selected doc ), round(float(par[0]), 5), round(float(par[1]), 5), - ) + ), ) elif line.startswith("-Circle"): data = line.replace("-Circle (Radius : ", "").replace("))\n", "") @@ -639,72 +624,70 @@ def cmpPos(doc=None): ## compare exported positions with the selected doc ), 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( + 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): # print(d) # diff_content = a_content + b_content try: - f = open(home + r"\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") FreeCADGui.Selection.clearSelection() @@ -753,7 +736,7 @@ def cmpPos(doc=None): ## compare exported positions with the selected doc if len(pcbN) > 0: FreeCADGui.ActiveDocument.getObject(pcbN).Transparency = old_pcb_tval generateSketch = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUpGui").GetBool( - "generate_sketch" + "generate_sketch", ) if generate_sketch and generateSketch: if len(sk_add) > 0: @@ -761,16 +744,8 @@ def cmpPos(doc=None): ## compare exported positions with the selected doc 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, - ) + 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) diff --git a/explode.py b/explode.py index a6d1f3d..d5259ad 100644 --- a/explode.py +++ b/explode.py @@ -1,4 +1,3 @@ - # Form implementation generated from reading ui file 'C:\Cad\Progetti_K\3D-FreeCad-tools\explode.ui' # # Created: Fri Sep 21 14:09:48 2018 @@ -55,9 +54,8 @@ def get_top_level(obj): 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 @@ -266,15 +264,14 @@ def explode_pcb(pos): docG.getObject(o.Name).Transparency = 50 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 - 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(): @@ -354,7 +351,7 @@ def Exp_putOnTopRightCorner(): resolution = QtGui.QDesktopWidget().screenGeometry() margin = 80 xp = (resolution.width()) - sizeX - margin / 5 # - (KSUWidget.frameSize().width() / 2) - ((resolution.height()) - sizeY - margin) # - (KSUWidget.frameSize().height() / 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) @@ -373,7 +370,7 @@ def runExplodeGui(): explode_dwg.setObjectName("ksuExplode") explode_dwg.raise_() explode_dwg.setFeatures( - QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable + QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable, ) # | QtGui.QDockWidget.DockWidgetClosable ) # RHDockWidget.destroyed.connect(onDestroy) diff --git a/fps.py b/fps.py index f63dd67..fffcfc1 100644 --- a/fps.py +++ b/fps.py @@ -45,7 +45,7 @@ def getFCversion(): FC_minorV = int(float(FreeCAD.Version()[1])) try: FC_git_Nbr = int( - float(FreeCAD.Version()[2].strip(" (Git)").split(" ")[0]) + float(FreeCAD.Version()[2].strip(" (Git)").split(" ")[0]), ) # +int(FreeCAD.Version()[2].strip(" (Git)").split(' ')[1]) except: FC_git_Nbr = 0 @@ -112,8 +112,6 @@ def makeAnno(name, bp, txt, afs): return anno - - def crc_gen_t(data): import binascii import re @@ -133,6 +131,9 @@ def make_unicode_t(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): @@ -193,15 +194,11 @@ def extrude_holes(holes, w): FreeCADGui.ActiveDocument.getObject(holes.Name).Visibility = False - - def cut_fuzzy(base, tool, ftol): Part.show(base.Shape.cut(tool.Shape, ftol)) - - def cut_out_tracks(pcbsk, tracks, tname_sfx): # import tracks; import importlib;importlib.reload(tracks) @@ -259,7 +256,7 @@ def cut_out_tracks(pcbsk, tracks, tname_sfx): 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 + Common_Top.Name, ).Shape new_label = tracks.Label + "_cut" FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(Common_Top.Name).ShapeColor @@ -267,10 +264,10 @@ def cut_out_tracks(pcbsk, tracks, tname_sfx): 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 + Common_Top.Name, ).DiffuseColor FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject( - Common_Top.Name + Common_Top.Name, ).Transparency FreeCAD.ActiveDocument.ActiveObject.Label = new_label tracks_ct_Name = FreeCAD.ActiveDocument.ActiveObject.Name @@ -309,7 +306,7 @@ def simple_cpy(obj, lbl): # removesubtree(FreeCADGui.Selection.getSelection()) # -from fcad_parser import KicadPCB +from fcad_parser import KicadPCB # noqa: F811 from kicadStepUptools import make_string, make_unicode, removesubtree start_f = """(kicad_pcb (version 20211014) (generator pcbnew) @@ -362,7 +359,6 @@ def addfootprint(fname=None): global start_time, last_pcb_path, min_drill_size global tracks_version global start_f, end_f, deltaz - FreeCAD.Console.PrintMessage("kicad_parser_version " + kicad_parser.__kicad_parser_version__ + "\n") # maui # cfg_read_all() it doesn't work through different files @@ -370,7 +366,6 @@ def addfootprint(fname=None): FreeCAD.Console.PrintMessage("footprints version: " + fps_version + "\n") - Filter = "" pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp") if fname is None: last_pcb_path = pg.GetString("last_pcb_path") @@ -379,8 +374,11 @@ def addfootprint(fname=None): 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" + fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( + None, + "Open File...", + make_unicode(last_pcb_path), + "*.kicad_mod", ) else: fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( @@ -390,7 +388,7 @@ def addfootprint(fname=None): "*.kicad_mod", options=QtWidgets.QFileDialog.DontUseNativeDialog, ) - path, _name = os.path.split(fname) + _path, _name = os.path.split(fname) # filename=os.path.splitext(name)[0] filename = fname # importDXF.open(os.path.join(dirname,filename)) @@ -420,10 +418,6 @@ def addfootprint(fname=None): # print(pcb_color_pos) pcb_transparency = 80 pcb_col = assign_col[pcb_color_pos] - if pcb_color_pos == 9: - pass - else: - pass 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) @@ -442,8 +436,7 @@ def addfootprint(fname=None): # lines = start_f+lines+end_f import tempfile - tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".kicad_pcb") - with tmp 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")) @@ -623,7 +616,10 @@ def addfootprint(fname=None): consolePrint("making Top Pads\n") pcb.setLayer(0) #'F.Cu') topP = pcb.makePads( - shape_type="wire", thickness=deltaz, holes=False, fit_arcs=True + shape_type="wire", + thickness=deltaz, + holes=False, + fit_arcs=True, ) # solid',thickness=deltaz,holes=True,fit_arcs=True) topPf = None topPe = None @@ -900,11 +896,7 @@ def addfootprint(fname=None): pcb_XL, pcb_YL, pcb_ZL, - FreeCAD.Vector( - centerX - pcb_XL / 2, - centerY - pcb_YL / 2, - -(pcb_ZL + deltaz), - ), + FreeCAD.Vector(centerX - pcb_XL / 2, centerY - pcb_YL / 2, -(pcb_ZL + deltaz)), FreeCAD.Vector(0, 0, 1), ).cut(holesT.Shape) removesubtree([holesT]) @@ -913,11 +905,7 @@ def addfootprint(fname=None): pcb_XL, pcb_YL, pcb_ZL, - FreeCAD.Vector( - centerX - pcb_XL / 2, - centerY - pcb_YL / 2, - -(pcb_ZL + deltaz), - ), + FreeCAD.Vector(centerX - pcb_XL / 2, centerY - pcb_YL / 2, -(pcb_ZL + deltaz)), FreeCAD.Vector(0, 0, 1), ) pcb.ViewObject.Transparency = pcb_transparency diff --git a/kicadStepUpCMD.py b/kicadStepUpCMD.py index d62b7bf..422220a 100644 --- a/kicadStepUpCMD.py +++ b/kicadStepUpCMD.py @@ -126,8 +126,6 @@ def fuse_objs(GuiObjSel): return MultiFuseName - - def rmvsubtree(objs): def addsubobjs(obj, toremoveset): toremove.add(obj) @@ -178,10 +176,9 @@ def getTopLevel(obj): 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) + if hasattr(ap, "Placement") and len(ap.InListRecursive) < lvl: + top = ap + lvl = len(ap.InListRecursive) # else: # sayerr(obj.Label) # top = obj @@ -266,11 +263,7 @@ def getNormalPlacementHierarchy(sel0): 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 = 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 @@ -302,11 +295,7 @@ def getNormalPlacementHierarchy(sel0): 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), - ) + 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() @@ -381,11 +370,7 @@ def getNormalPlacementHierarchy(sel0): 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 = 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 @@ -481,8 +466,7 @@ def ksu_edges2sketch(): ow = e.OuterWire wires.append(ow) # es = ow.Edges - for _e in ow.Edges: - cp_edges.append(_e) + cp_edges.extend(ow.Edges) Part.show(ow) cp = doc.ActiveObject cp_edges_obj.append(cp) @@ -505,8 +489,7 @@ def ksu_edges2sketch(): 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) @@ -624,10 +607,7 @@ def ksu_edges2sketch(): for _e in union.Shape.Edges: if isinstance(_e.Curve, (Part.Line, Part.LineSegment)): sketch.addGeometry( - P_Line( - Base.Vector(_e.firstVertex().Point), - Base.Vector(_e.lastVertex().Point), - ) + P_Line(Base.Vector(_e.firstVertex().Point), Base.Vector(_e.lastVertex().Point)), ) # sketch.addGeometry(_e.Curve) if attach_sketch: @@ -678,7 +658,7 @@ def ksu_edges2sketch(): 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" + "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) @@ -774,7 +754,7 @@ def setupUi(self, CDialog): 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("") @@ -782,7 +762,7 @@ def setupUi(self, CDialog): 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) @@ -812,11 +792,7 @@ def setupUi(self, CDialog): self.coincident.setToolTip(translate("Ui_CDialog", "Lock Coincident")) self.coincident.setText("") icon1 = QtGui.QIcon() - icon1.addPixmap( - QtGui.QPixmap("Sketcher_LockCoincident.png"), - QtGui.QIcon.Normal, - QtGui.QIcon.Off, - ) + icon1.addPixmap(QtGui.QPixmap("Sketcher_LockCoincident.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.coincident.setIcon(icon1) self.coincident.setIconSize(QtCore.QSize(48, 48)) self.coincident.setChecked(False) @@ -891,14 +867,7 @@ def setupUi(self, CDialog): def return_strings(self): # 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(), - ], - ) + return map(str, [self.tolerance.text(), self.all_constraints.isChecked(), self.rmvXGeo.isChecked()]) # @staticmethod # def get_data(parent=None): @@ -918,7 +887,8 @@ class ksuTools: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "kicad-StepUp-icon.svg" + 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"), @@ -930,7 +900,6 @@ def IsActive(self): # else: # return True # import kicadStepUptools - return True def Activated(self): @@ -959,7 +928,8 @@ def GetResources(self): ) return { "Pixmap": os.path.join( - ksuWB_icons_path, "Sketcher_CreatePolyline-RF.svg" + ksuWB_icons_path, + "Sketcher_CreatePolyline-RF.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -1034,14 +1004,11 @@ def __init__(self, xs, ys, xe, ye): FreeCAD.ActiveDocument.removeObject(mFuseNm) else: FreeCAD.ActiveDocument.addObject("Part::Refine", "Refined").Source = FreeCAD.ActiveDocument.getObject( - mFuseNm + mFuseNm, ) RefName = FreeCAD.ActiveDocument.ActiveObject.Name FreeCAD.ActiveDocument.recompute() - sv0 = Draft.makeShape2DView( - FreeCAD.ActiveDocument.getObject(RefName), - FreeCAD.Vector(-0.0, -0.0, 1.0), - ) + 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) @@ -1056,25 +1023,14 @@ def __init__(self, xs, ys, xe, ye): FreeCAD.ActiveDocument.removeObject(mFuseNm) FreeCAD.ActiveDocument.recompute() # creating an edge ordered sketch - sv0 = Draft.makeShape2DView( - FreeCAD.ActiveDocument.getObject(sk.Name), - FreeCAD.Vector(-0.0, -0.0, 1.0), - ) + 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) 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" FreeCAD.ActiveDocument.recompute() @@ -1101,7 +1057,8 @@ class ksuToolsMoveSketch: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Sketcher_Move.svg" + 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"), @@ -1122,10 +1079,7 @@ def Activated(self): ui = Ui_Offset_value() ui.setupUi(offsetDlg) ui.offset_label.setText( - translate( - "ksu", - "Select a Sketch and Parameters to
    move the sketch.
    Offset X:", - ) + 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]:") @@ -1135,7 +1089,7 @@ def Activated(self): ui.checkBox.setVisible(True) ui.checkBox.setChecked(False) ui.checkBox.setToolTip( - "reset Placement of Sketch,\nmoving the internal geometry\nignoring offset imput fields" + "reset Placement of Sketch,\nmoving the internal geometry\nignoring offset imput fields", ) reply = offsetDlg.exec_() skip = False @@ -1157,9 +1111,7 @@ def Activated(self): if not skip: 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 @@ -1184,7 +1136,8 @@ class ksuToolsOffset2D: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Offset2D.svg" + 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"), @@ -1208,10 +1161,7 @@ def Activated(self): 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" + offset_method = "Arc" if ui.checkBox.isChecked() else "Intersection" doc.openTransaction("off2D") f = doc.addObject("Part::Offset2D", "Offset2D") f.Source = sel[0] # some object @@ -1239,7 +1189,8 @@ 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" + ksuWB_icons_path, + "Part_Extrude.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -1273,7 +1224,8 @@ def GetResources(self): ) return { "Pixmap": os.path.join( - ksuWB_icons_path, "Sketcher_Validate.svg" + ksuWB_icons_path, + "Sketcher_Validate.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -1303,7 +1255,8 @@ class ksuToolsOpenBoard: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "importBoard.svg" + 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"), @@ -1345,7 +1298,8 @@ class ksuToolsLoadFootprint: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "importFP.svg" + 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"), @@ -1384,7 +1338,8 @@ class ksuToolsExportModel: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "export3DModel.svg" + 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"), @@ -1440,7 +1395,8 @@ class ksuToolsImport3DStep: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "add_block_y.svg" + 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"), @@ -1477,7 +1433,8 @@ class ksuToolsExport3DStep: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "export3DStep.svg" + 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"), @@ -1549,7 +1506,8 @@ class ksuToolsMakeCompound: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "compound.svg" + 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"), @@ -1586,7 +1544,8 @@ class ksuToolsPushPCB: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Sketcher_Rectangle.svg" + 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"), @@ -1730,7 +1689,8 @@ class ksuToolsPullPCB: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Sketcher_Pull.svg" + 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"), @@ -1773,7 +1733,8 @@ class ksuToolsPushMoved: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "PushMoved.svg" + 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"), @@ -1816,7 +1777,8 @@ class ksuToolsPullMoved: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "PullMoved.svg" + 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"), @@ -1858,7 +1820,8 @@ class ksuAsm2Part: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Assembly_To_Part.svg" + 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"), @@ -1868,9 +1831,7 @@ def IsActive(self): import FreeCADGui # if a3: - if "LinkView" in dir(FreeCADGui): # pre a3 Link3 merge - return True - return False + return "LinkView" in dir(FreeCADGui) # pre a3 Link3 merge def Activated(self): # do something here... @@ -2000,7 +1961,8 @@ class ksuToolsSync3DModels: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Sync3Dmodels.svg" + 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( @@ -2046,7 +2008,8 @@ class ksuToolsGeneratePositions: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "File_Positions.svg" + 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( @@ -2056,12 +2019,7 @@ def GetResources(self): } 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... @@ -2084,7 +2042,8 @@ class ksuToolsComparePositions: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Compare_Positions.svg" + 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( @@ -2094,12 +2053,7 @@ def GetResources(self): } 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... @@ -2142,7 +2096,8 @@ class ksuToolsCollisions: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "collisions.svg" + 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"), @@ -2207,16 +2162,8 @@ def Activated(self): 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: QtGui.QMessageBox.information( None, @@ -2233,7 +2180,6 @@ def Activated(self): FreeCAD.Console.PrintError("select something\nto project it to a 2D shape in the document\n") - FreeCADGui.addCommand("ksuTools3D2D", ksuTools3D2D()) @@ -2244,7 +2190,8 @@ class ksuToolsTurnTable: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "texture_turntable.svg" + 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"), @@ -2308,7 +2255,8 @@ class ksuToolsConstrainator: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Sketcher_LockAll.svg" + 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"), @@ -2337,15 +2285,9 @@ def Activated(self): if tol <= 0: tol = 0.01 if i == 1: - if "True" in dv: - constr = "all" - else: - constr = "coincident" + constr = "all" if "True" in dv else "coincident" if i == 2: - if "True" in dv: - rmvXG = True - else: - rmvXG = False + rmvXG = "True" in dv if rmvXG: sanitizeSkBsp(sel[0].Name, tol) add_constraints(sel[0].Name, tol, constr) @@ -2387,7 +2329,8 @@ class ksuToolsDiscretize: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Discretize.svg" + 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"), @@ -2415,16 +2358,8 @@ def Activated(self): 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, - ) + 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() @@ -2441,7 +2376,8 @@ class ksuToolsEdges2Sketch: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Edges2Sketch.svg" + 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( @@ -2480,7 +2416,8 @@ class ksuToolsResetPartPlacement: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "resetPartPlacement.svg" + 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( @@ -2525,9 +2462,7 @@ def Activated(self): 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(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 @@ -2537,7 +2472,8 @@ def Activated(self): 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) + 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: @@ -2567,7 +2503,8 @@ def Activated(self): ) # store the object pointer with its global placement elif o.TypeId == "App::Link": plc = Part.getShape( - o.Parents[0][0], o.Parents[0][1] + o.Parents[0][0], + o.Parents[0][1], ).Placement # getLinkGlobalPlacement(o) # print(o.Label+' App::Link') # print(plc) @@ -2584,13 +2521,11 @@ def Activated(self): 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 + 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) + 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: @@ -2635,11 +2570,7 @@ def IsActive(self): sel = FreeCADGui.Selection.getSelection() if len(sel) > 1 or len(sel) == 0: return False - if len(sel) == 1: - if hasattr(sel[0], "TypeId"): - if (sel[0].TypeId) != "App::Part": - return False - return True + return not (len(sel) == 1 and hasattr(sel[0], "TypeId") and sel[0].TypeId != "App::Part") FreeCADGui.addCommand("ksuToolsResetPartPlacement", ksuToolsResetPartPlacement()) @@ -2652,7 +2583,8 @@ class ksuToolsResetPlacement: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "resetPlacement.svg" + 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"), @@ -2693,7 +2625,8 @@ class ksuTools2D2Sketch: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "2DtoSketch.svg" + 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"), @@ -2721,7 +2654,11 @@ def Activated(self): 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")), []) + 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) @@ -2748,7 +2685,7 @@ def Activated(self): "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" + "Select edge elements to be converted to Sketch\nBSplines and Bezier curves are not supported by this tool\n", ) stop sk.Label = "Sketch_converted" @@ -2767,11 +2704,7 @@ def Activated(self): except: sname = FreeCAD.ActiveDocument.ActiveObject.Name FreeCAD.ActiveDocument.removeObject(sname) - QtGui.QMessageBox.information( - None, - "Error", - "BSplines not supported in FC0.16\nUse FC0.17", - ) + 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) @@ -2865,25 +2798,13 @@ def Activated(self): sk = None sk = Draft.makeSketch(FreeCADGui.Selection.getSelection(), autoconstraints=True) if sk is None: - 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, - ) + 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): @@ -2901,7 +2822,6 @@ def Activated(self): FreeCAD.Console.PrintWarning("Select elements to be converted to Sketch\n") - FreeCADGui.addCommand("ksuTools2D2Sketch", ksuTools2D2Sketch()) @@ -2912,7 +2832,8 @@ class ksuTools2DtoFace: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "2DtoFace.svg" + 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"), @@ -2925,7 +2846,11 @@ def Activated(self): # do something here... if FreeCADGui.Selection.getSelection(): try: - edges = functools.reduce(operator.iadd, (obj.Shape.Edges for obj in FreeCADGui.Selection.getSelection() if hasattr(obj, "Shape")), []) + 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 @@ -2962,7 +2887,8 @@ class ksuToolsSimplifySketck: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "SimplifySketch.svg" + 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"), @@ -2996,7 +2922,8 @@ class ksuToolsBsplineNormalize: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Sketcher_BSplineNormalize.svg" + 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( @@ -3033,7 +2960,8 @@ class ksuToolsFootprintGen: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "exportFootprint.svg" + 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"), @@ -3074,7 +3002,8 @@ class ksuToolsStepImportModeSTD: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "ImportModeSTD.svg" + 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"), @@ -3112,13 +3041,11 @@ class ksuToolsStepImportModeComp: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "ImportModeSimplified.svg" + 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", - ), + "ToolTip": QT_TRANSLATE_NOOP("ksuToolsStepImportModeComp", "ksu tools disable Simplified STEP Import Mode"), } def IsActive(self): @@ -3153,7 +3080,8 @@ class ksuToolsCopyPlacement: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Placement_Copy.svg" + 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"), @@ -3200,7 +3128,8 @@ class ksuToolsColoredClone: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "CloneYlw.svg" + 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"), @@ -3218,6 +3147,9 @@ def mk_str(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" @@ -3242,31 +3174,22 @@ def mk_str(input): # 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 + obj_tocopy.Name, ).ShapeColor - if hasattr( - FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), - "LineColor", - ): + if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "LineColor"): FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject( - obj_tocopy.Name + obj_tocopy.Name, ).LineColor FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject( - obj_tocopy.Name + obj_tocopy.Name, ).PointColor - if hasattr( - FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), - "DiffuseColor", - ): + if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "DiffuseColor"): FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject( - obj_tocopy.Name + obj_tocopy.Name, ).DiffuseColor - if hasattr( - FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), - "Transparency", - ): + if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "Transparency"): FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject( - obj_tocopy.Name + obj_tocopy.Name, ).Transparency else: FreeCAD.Console.PrintWarning("missing copy of color attributes") @@ -3290,7 +3213,8 @@ class ksuToolsColoredBinder: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "SubShapeBinderYlw.svg" + 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"), @@ -3308,6 +3232,9 @@ def mk_str(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" @@ -3335,31 +3262,22 @@ def mk_str(input): # 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 + obj_tocopy.Name, ).ShapeColor - if hasattr( - FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), - "LineColor", - ): + if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "LineColor"): FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject( - obj_tocopy.Name + obj_tocopy.Name, ).LineColor FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject( - obj_tocopy.Name + obj_tocopy.Name, ).PointColor - if hasattr( - FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), - "DiffuseColor", - ): + if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "DiffuseColor"): FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject( - obj_tocopy.Name + obj_tocopy.Name, ).DiffuseColor - if hasattr( - FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), - "Transparency", - ): + if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "Transparency"): FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject( - obj_tocopy.Name + obj_tocopy.Name, ).Transparency else: FreeCADGui.ActiveDocument.ActiveObject.Transparency = 60 @@ -3373,11 +3291,7 @@ def mk_str(input): # FreeCAD.Console.PrintWarning("Select object with a \"Shape\" to be copied!\n") else: # 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!", - ) + 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") @@ -3392,7 +3306,8 @@ class ksuToolsReLinkBinder: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "SubShapeBinderRelink.svg" + 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( @@ -3413,6 +3328,9 @@ def mk_str(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" @@ -3453,7 +3371,8 @@ class ksuToolsUnion: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Geofeature-Fuse.svg" + 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"), @@ -3472,6 +3391,9 @@ def mk_str(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") @@ -3532,7 +3454,8 @@ class ksuToolsSimpleCopy: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "simple_copy.svg" + 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"), @@ -3550,6 +3473,9 @@ def mk_str(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: @@ -3562,7 +3488,8 @@ def mk_str(input): cp_label = mk_str(obj_tocopy.Label) + "_sc" if hasattr(FreeCAD.ActiveDocument.getObject(obj_tocopy.Name), "Shape"): FreeCAD.ActiveDocument.addObject( - "Part::Feature", cp_label + "Part::Feature", + cp_label, ).Shape = FreeCAD.ActiveDocument.getObject(obj_tocopy.Name).Shape newObj = FreeCAD.ActiveDocument.ActiveObject newObjV = FreeCADGui.ActiveDocument.ActiveObject @@ -3584,28 +3511,19 @@ def mk_str(input): # 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", - ): + 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", - ): + 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 + subobj.Name, ).DiffuseColor - if hasattr( - FreeCADGui.ActiveDocument.getObject(subobj.Name), - "Transparency", - ): + 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 + subobj.Name, ).Transparency elif hasattr( FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), @@ -3616,29 +3534,20 @@ def mk_str(input): # 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 + obj_tocopy.Name, ).ShapeColor - if hasattr( - FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), - "LineColor", - ): + if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "LineColor"): FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject( - obj_tocopy.Name + obj_tocopy.Name, ).LineColor FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject( - obj_tocopy.Name + obj_tocopy.Name, ).PointColor - if hasattr( - FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), - "DiffuseColor", - ): + 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", - ): + if hasattr(FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name), "Transparency"): FreeCADGui.ActiveDocument.ActiveObject.Transparency = ( FreeCADGui.ActiveDocument.getObject(obj_tocopy.Name).Transparency ) @@ -3669,7 +3578,8 @@ class ksuToolsDeepCopy: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "deep_copy.svg" + 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( @@ -3679,9 +3589,9 @@ def GetResources(self): } 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 - 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... @@ -3719,6 +3629,9 @@ def mk_str_u(input): if isinstance(input, str): return input return input.encode("utf-8") + if type(input) == unicode: + return input.encode("utf-8") + return input ### @@ -3748,20 +3661,16 @@ def deep_copy_part(doc, part, compound="flat", suffix="(copy)"): copied_subobjects_Names = [] # 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 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) @@ -3886,11 +3795,9 @@ def addsubobjs(obj, totoggleset): 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)] @@ -3946,7 +3853,8 @@ class ksuToolsRemoveFromTree: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "TreeItemOutMinus.svg" + 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( @@ -3989,9 +3897,7 @@ def Activated(self): o.Placement = base.Placement.multiply(o.Placement) for item in base.InListRecursive: # fcc_prn(item.Label) - if ( - item.TypeId in {"App::Part", "PartDesign::Body", "App::LinkGroup"} - ): + 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)) item.addObject(o) @@ -4027,7 +3933,8 @@ class ksuToolsAddToTree: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "TreeItemInPlus.svg" + 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( @@ -4051,9 +3958,7 @@ def Activated(self): if o.Name != sel[0].Name: if hasattr(base, "OutList"): for item in base.InListRecursive: - if ( - item.TypeId in {"App::Part", "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) @@ -4131,7 +4036,8 @@ class ksuToolsTransparencyToggle: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "transparency_toggle.svg" + 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"), @@ -4158,11 +4064,7 @@ def Activated(self): toggle_transparency_subtree(FreeCADGui.Selection.getSelection()) else: # 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!", - ) + 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") @@ -4178,7 +4080,8 @@ class ksuToolsVisibilityRestore: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "restoreVisibility.svg" + 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"), @@ -4210,15 +4113,14 @@ def Activated(self): # doc.getObject(obj.Name).Transparency = 0 else: for o in doc.getObject(obj.Name).OutListRecursive: - if not o.ViewObject.Visibility: - if ( - 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) + 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) for nm in invisible_objs: @@ -4251,7 +4153,8 @@ class ksuToolsHighlightToggle: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "select_toggle.svg" + 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"), @@ -4287,7 +4190,8 @@ class ksuToolsVisibilityToggle: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "visibility_toggle.svg" + 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"), @@ -4319,7 +4223,8 @@ class ksuToolsCheckSolid: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "ShapeInfo_check.svg" + 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"), @@ -4337,6 +4242,9 @@ def mk_str(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) @@ -4451,7 +4359,8 @@ class ksuToolsToggleTreeView: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "expand_all.svg" + 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"), @@ -4566,7 +4475,8 @@ def GetResources(self): mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsCaliper", "Manipulator tools 'Caliper'") return { "Pixmap": os.path.join( - ksuWB_icons_path, "Caliper.svg" + ksuWB_icons_path, + "Caliper.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -4606,7 +4516,8 @@ def GetResources(self): ) return { "Pixmap": os.path.join( - ksuWB_icons_path, "Path-SelectLoop.svg" + ksuWB_icons_path, + "Path-SelectLoop.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -4641,7 +4552,8 @@ def GetResources(self): mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsMergeSketches", "Merge Sketches") return { "Pixmap": os.path.join( - ksuWB_icons_path, "Sketcher_MergeSketch.svg" + ksuWB_icons_path, + "Sketcher_MergeSketch.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -4676,7 +4588,8 @@ def GetResources(self): mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsEditPrefs", "Edit Preferences") return { "Pixmap": os.path.join( - ksuWB_icons_path, "Preferences-Edit.svg" + ksuWB_icons_path, + "Preferences-Edit.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -4710,7 +4623,8 @@ def GetResources(self): mybtn_tooltip = QT_TRANSLATE_NOOP("ksuOpDXF", "open Legacy DXF") return { "Pixmap": os.path.join( - ksuWB_icons_path, "openDXF.svg" + ksuWB_icons_path, + "openDXF.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip + " v1.4.0", @@ -4740,8 +4654,11 @@ def Activated(self): 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" + name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( + None, + "Open a DXF file...", + last_pcb_path, + filter="*.dxf *.DXF", ) else: name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( @@ -4770,7 +4687,8 @@ def GetResources(self): mybtn_tooltip = QT_TRANSLATE_NOOP("ksuOpEzDXF", "open ezDXF") return { "Pixmap": os.path.join( - ksuWB_icons_path, "openEzDXF.svg" + ksuWB_icons_path, + "openEzDXF.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -4801,7 +4719,7 @@ def Activated(self): 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( + name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( None, "Open a DXF file (w ezDXF lib)...", last_pcb_path, @@ -4836,7 +4754,8 @@ def GetResources(self): mybtn_tooltip = QT_TRANSLATE_NOOP("ksuImpDXF", "Import Legacy DXF") return { "Pixmap": os.path.join( - ksuWB_icons_path, "importDXF.svg" + ksuWB_icons_path, + "importDXF.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip + " v1.4.0", @@ -4866,8 +4785,11 @@ def Activated(self): 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" + name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( + None, + "Import a DXF file...", + last_pcb_path, + filter="*.dxf *.DXF", ) else: name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( @@ -4899,7 +4821,8 @@ def GetResources(self): mybtn_tooltip = "export Legacy DXF" return { "Pixmap": os.path.join( - ksuWB_icons_path, "exportDXF.svg" + ksuWB_icons_path, + "exportDXF.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -4931,7 +4854,8 @@ def GetResources(self): mybtn_tooltip = QT_TRANSLATE_NOOP("ksuRemoveTimeStamp", "Remove TimeStamp from Labels") return { "Pixmap": os.path.join( - ksuWB_icons_path, "remove_TimeStamp.svg" + ksuWB_icons_path, + "remove_TimeStamp.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -4939,11 +4863,10 @@ def GetResources(self): 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 # else: # self.setToolTip("Grayed Tooltip!") @@ -5019,7 +4942,8 @@ def GetResources(self): mybtn_tooltip = QT_TRANSLATE_NOOP("ksuRemoveSuffix", "Remove 'custom' Suffix from Labels") return { "Pixmap": os.path.join( - ksuWB_icons_path, "RemoveSuffix.svg" + ksuWB_icons_path, + "RemoveSuffix.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -5027,11 +4951,10 @@ def GetResources(self): 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): @@ -5145,7 +5068,8 @@ def GetResources(self): ) return { "Pixmap": os.path.join( - ksuWB_icons_path, "Explode_Pcb.svg" + ksuWB_icons_path, + "Explode_Pcb.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -5173,7 +5097,8 @@ def GetResources(self): mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsDefeaturingTools", "Defeaturing Tools from Defeaturing WorkBench") return { "Pixmap": os.path.join( - ksuWB_icons_path, "DefeaturingTools.svg" + ksuWB_icons_path, + "DefeaturingTools.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -5210,7 +5135,8 @@ def GetResources(self): mybtn_tooltip = QT_TRANSLATE_NOOP("ksuToolsRemoveSubTree", "Remove Sub Tree") return { "Pixmap": os.path.join( - ksuWB_icons_path, "RemoveSubtree.svg" + ksuWB_icons_path, + "RemoveSubtree.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -5268,10 +5194,7 @@ def Activated(self): import tracks from kicadStepUptools import ZoomFitThread, removesubtree, restore_specular, restore_specular_cls - if FreeCAD.ActiveDocument is not None: - doc = FreeCAD.ActiveDocument - else: - doc = FreeCAD.newDocument() + doc = FreeCAD.ActiveDocument if FreeCAD.ActiveDocument is not None else FreeCAD.newDocument() # doc.commitTransaction() # doc.UndoMode = 1 doc.openTransaction("add_tracks_kicad") @@ -5287,7 +5210,6 @@ def Activated(self): def removing_objs(): """removing objects after delay""" - doc.openTransaction("rmv_tracks_kicad") for tbr in add_toberemoved: removesubtree(tbr) @@ -5336,10 +5258,7 @@ def Activated(self): # do something here... import makefacedxf - if FreeCAD.ActiveDocument is not None: - doc = FreeCAD.ActiveDocument - else: - doc = FreeCAD.newDocument() + 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() @@ -5460,10 +5379,7 @@ def Activated(self): # reload( kicadStepUptools ) if reload_Gui: reload_lib(kicadStepUptools) - from kicadStepUptools import ( - create_axis, - open, - ) # onLoadBoard, onLoadFootprint + from kicadStepUptools import create_axis, open # onLoadBoard, onLoadFootprint if ext.lower() == ".kicad_mod": dname = (demo_model).split(".", maxsplit=1)[0].replace("-", "_") @@ -5528,7 +5444,8 @@ def GetResources(self): ) return { "Pixmap": os.path.join( - ksuWB_icons_path, "Import-Export-STEP.svg" + ksuWB_icons_path, + "Import-Export-STEP.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -5610,7 +5527,8 @@ 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" + ksuWB_icons_path, + "Restore_Transparency.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -5622,12 +5540,11 @@ def Activated(self): FreeCAD.Console.Print("No Active Document found") return 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 + 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): @@ -5645,7 +5562,8 @@ 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" + ksuWB_icons_path, + "arc2circle.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -5664,10 +5582,9 @@ def Activated(self): 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 + if c == g.Center and g.Radius == rads[i]: + found = True + continue if not found: centers.append(g.Center) rads.append(g.Radius) @@ -5679,7 +5596,7 @@ def Activated(self): # 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]) + 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() @@ -5704,7 +5621,8 @@ def GetResources(self): ) return { "Pixmap": os.path.join( - ksuWB_icons_path, "Three-Points-Center.svg" + 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, @@ -5772,11 +5690,7 @@ def circle_center(A, B, C): 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, - ) + 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: @@ -5784,20 +5698,12 @@ def circle_center(A, B, C): 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, - ) + 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") nP = FreeCAD.ActiveDocument.ActiveObject.Parents[0][0] @@ -5836,7 +5742,8 @@ 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" + ksuWB_icons_path, + "BoundBox.svg", ), # the name of a svg file available in the resources "MenuText": mybtn_tooltip, "ToolTip": mybtn_tooltip, @@ -5844,11 +5751,10 @@ def GetResources(self): 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): @@ -5921,7 +5827,7 @@ def make_shape_from_mesh(d, m): else: bbO.Height = 0.01 FreeCAD.Console.PrintMessage( - "BB data x:" + str(bb.XLength) + ", y:" + str(bb.YLength) + ", z:" + str(bb.ZLength) + "\n" + "BB data x:" + str(bb.XLength) + ", y:" + str(bb.YLength) + ", z:" + str(bb.ZLength) + "\n", ) FreeCAD.ActiveDocument.recompute() FreeCADGui.SendMsgToActiveView("ViewFit") @@ -5931,26 +5837,25 @@ def make_shape_from_mesh(d, m): cmpd_objs = [] toDel_objs = [] for o in sel: - if hasattr(o.ViewObject, "Visibility"): - if 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) + 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 @@ -5979,7 +5884,7 @@ def make_shape_from_mesh(d, m): else: bbO.Height = 0.01 FreeCAD.Console.PrintMessage( - "BB data x:" + str(bb.XLength) + ", y:" + str(bb.YLength) + ", z:" + str(bb.ZLength) + "\n" + "BB data x:" + str(bb.XLength) + ", y:" + str(bb.YLength) + ", z:" + str(bb.ZLength) + "\n", ) doc.recompute() for o in cmpd_objs: @@ -6001,7 +5906,8 @@ class ksuToolsImportFootprint: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "importFPs.svg" + 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"), @@ -6045,7 +5951,8 @@ class ksuToolsSelection2Edges: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "Select_edges.svg" + 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"), @@ -6083,7 +5990,8 @@ class ksuToolsAlignView: def GetResources(self): return { "Pixmap": os.path.join( - ksuWB_icons_path, "AlignView2Face.svg" + 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"), @@ -6091,12 +5999,11 @@ def GetResources(self): 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 + 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): @@ -6133,34 +6040,33 @@ def pointAt(normal, up): # 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) - 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)) + 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) + 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 510bbd9..2d59f6d 100644 --- a/kicadStepUptools.py +++ b/kicadStepUptools.py @@ -66,7 +66,7 @@ # * 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 +##With kicad StepUp you'll get an exact representation of your physical board in Native 3D PCB ## kicad StepUp tools ##done @@ -480,14 +480,13 @@ # 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 pivy.coin import SoDirectionalLight -# import configparser #utf-8 -# from codecs import open #maui to verify - pythonopen = builtin.open # to distinguish python built-in open function from the one declared here ## Constant definitions @@ -758,7 +757,6 @@ def collaps_Tree(): FreeCADGui.Selection.clearSelection() - ##-------------------------------------------------------------------------------------- py2 = False try: ## maui py3 @@ -783,19 +781,11 @@ def isConstruction(geo): # print(geo.Construction,'geo.Construction') return geo.Construction # print('geo.Content',geo.Content) - if 'geometryModeFlags="00000000000000000000000000000010"' in geo.Content: - # print('geometryModeFlags', True) - return True - # print('geometryModeFlags', False) - return False - + 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 @@ -819,7 +809,7 @@ def getFCversion(): FC_minorV = int(float(FreeCAD.Version()[1])) try: FC_git_Nbr = int( - float(FreeCAD.Version()[2].strip(" (Git)").split(" ")[0]) + float(FreeCAD.Version()[2].strip(" (Git)").split(" ")[0]), ) # +int(FreeCAD.Version()[2].strip(" (Git)").split(' ')[1]) except: FC_git_Nbr = 0 @@ -828,9 +818,8 @@ def getFCversion(): 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 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: @@ -840,18 +829,14 @@ def getFCversion(): 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 -try: - # use_Links=True #False +with contextlib.suppress(Exception): FreeCAD.Console.PrintWarning("Asm3 WB present\n") -except: - pass # FreeCAD.Console.PrintWarning('Asm3 WB not present\n') global export_board_2step @@ -1398,7 +1383,7 @@ def 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 @@ -1439,10 +1424,7 @@ def clear_console(): def close_ksu(): # def closeEvent(self, e): - msg = translate( - "Close", - "Do you want to quit? Have you saved your STEP artwork?
    ", - ) + 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) @@ -1489,10 +1471,7 @@ def tabify(): 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 = cv[0] if cv else None if KSUWidget and cv: t.findChildren(QtGui.QDockWidget) with contextlib.suppress(BaseException): @@ -1832,7 +1811,6 @@ def find_name(n): }.get(n, 0) # 0 is default if x not found - # import ConfigParser # import configobj @@ -1883,12 +1861,18 @@ def make_unicode(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 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): @@ -1983,11 +1967,11 @@ def simple_cpy_plc(obj, proot): # simple copy with incremental placement 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 + obj.Name, ).DiffuseColor if hasattr(FreeCADGui.ActiveDocument.getObject(obj.Name), "Transparency"): FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject( - obj.Name + obj.Name, ).Transparency new_label = make_string(obj.Label) + "_cp" FreeCAD.ActiveDocument.ActiveObject.Label = new_label @@ -2010,10 +1994,7 @@ def get_node_plc(o, obj): # get node placement in App::Part 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 + group = obj.OutList if "LinkGroup" in obj.TypeId else obj.Group # for o in obj.Group: # sayw(str(group)) for o in group: @@ -2098,8 +2079,8 @@ def retranslateUi(self, Dialog): ### def isWritable(path): try: - testfile = tempfile.TemporaryFile(dir=path) - testfile.close() + with tempfile.TemporaryFile(dir=path): + pass # sayw('ok') return True except: @@ -2140,7 +2121,7 @@ def comboBox_Changed(text_combo): + str(float(color_rgb[10]) * 255) + "," + str(float(color_rgb[11]) * 255) - + ");}" + + ");}", ) else: # say(str(material_index)+" here") @@ -2152,7 +2133,7 @@ def comboBox_Changed(text_combo): + str(shape_col[1] * 255) + "," + str(shape_col[2] * 255) - + ");}" + + ");}", ) @@ -2188,10 +2169,9 @@ def assignSTEPmaterials(objects, filepath): # 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: + for idc, mat_diff_col in enumerate(material_properties_diffuse): # say(mat_diff_col) delta_col = 0.01 if ( @@ -2204,7 +2184,6 @@ def assignSTEPmaterials(objects, filepath): material_index = idc found_mat = True # stop - idc += 1 ui.plainTextEdit.setStyleSheet( "#plainTextEdit {background-color:rgb(" + str(shape_col[0] * 255) @@ -2212,7 +2191,7 @@ def assignSTEPmaterials(objects, filepath): + str(shape_col[1] * 255) + "," + str(shape_col[2] * 255) - + ");}" + + ");}", ) ui.plainTextEdit_2.setStyleSheet( "#plainTextEdit_2 {background-color:rgb(" @@ -2221,7 +2200,7 @@ def assignSTEPmaterials(objects, filepath): + str(shape_col[1] * 255) + "," + str(shape_col[2] * 255) - + ");}" + + ");}", ) ui.comboBox.setCurrentIndex(material_index) color_list.append(shape_col) @@ -2234,10 +2213,7 @@ def assignSTEPmaterials(objects, filepath): reply = Dialog.exec_() # Dialog.exec_() # say(reply) - if reply == 1: - material = str(ui.comboBox.currentText()) - else: - material = "as is" + material = str(ui.comboBox.currentText()) if reply == 1 else "as is" color_list_mat.append(material) sayw(material) col_index = color_list.index(shape_col) @@ -2290,7 +2266,7 @@ def exportVRMLmaterials(objects, filepath): else: f.write(f"Shape {{ geometry IndexedFaceSet \n{{ creaseAngle {creaseAngle:.2f} coordIndex [") # write coordinate indexes for each face - f.write(",".join("%d,%d,%d,-1" % f for f in obj.faces)) + f.write(",".join(f"{f[0]},{f[1]},{f[2]},-1" for f in obj.faces)) f.write("]\n") # closes coordIndex f.write("coord Coordinate { point [") # write coordinate points for each vertex @@ -2305,10 +2281,9 @@ def exportVRMLmaterials(objects, filepath): # 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: + for idc, mat_diff_col in enumerate(material_properties_diffuse): # say(mat_diff_col) delta_col = 0.01 if ( @@ -2321,7 +2296,6 @@ def exportVRMLmaterials(objects, filepath): material_index = idc found_mat = True # stop - idc += 1 ## pal = QtGui.QPalette() ## bgc = QtGui.QColor(shape_col[0]*255,shape_col[1]*255, shape_col[2]*255) ## pal.setColor(QtGui.QPalette.Base, bgc) @@ -2333,7 +2307,7 @@ def exportVRMLmaterials(objects, filepath): + str(shape_col[1] * 255) + "," + str(shape_col[2] * 255) - + ");}" + + ");}", ) ui.plainTextEdit_2.setStyleSheet( "#plainTextEdit_2 {background-color:rgb(" @@ -2342,7 +2316,7 @@ def exportVRMLmaterials(objects, filepath): + str(shape_col[1] * 255) + "," + str(shape_col[2] * 255) - + ");}" + + ");}", ) ui.comboBox.setCurrentIndex(material_index) # ui.comboBox.clear() @@ -2357,10 +2331,7 @@ def exportVRMLmaterials(objects, filepath): reply = Dialog.exec_() # Dialog.exec_() # say(reply) - if reply == 1: - material = str(ui.comboBox.currentText()) - else: - material = "as is" + material = str(ui.comboBox.currentText()) if reply == 1 else "as is" color_list_mat.append(material) sayw(material) # else: @@ -2374,7 +2345,9 @@ def exportVRMLmaterials(objects, filepath): # say(color_list_mat[col_index]) if not Materials or color_list_mat[col_index] == "as is": shape_transparency = obj.transp - f.write("appearance Appearance{{material Material{{diffuseColor {:g} {:g} {:g}\n".format(*shape_col[:-1])) + f.write( + "appearance Appearance{{material Material{{diffuseColor {:g} {:g} {:g}\n".format(*shape_col[:-1]), + ) f.write(f"transparency {shape_transparency:g}}}}}") f.write("}\n") # closes Shape else: @@ -2441,7 +2414,7 @@ def exportVRML(objects, filepath): f.write(f"Shape {{ geometry IndexedFaceSet \n{{ creaseAngle {creaseAngle:.2f} coordIndex [") # f.write("Shape { geometry IndexedFaceSet \n{ coordIndex [") # write coordinate indexes for each face - f.write(",".join("%d,%d,%d,-1" % f for f in obj.faces)) + f.write(",".join(f"{f[0]},{f[1]},{f[2]},-1" for f in obj.faces)) f.write("]\n") # closes coordIndex f.write("coord Coordinate { point [") # write coordinate points for each vertex @@ -2482,10 +2455,7 @@ def export(componentObjs, fullfilePathName, scale=None, label=None): global exportV, applymaterials, ui, creaseAngle - if label is None: - exp_name = componentObjs[0].Label - else: - exp_name = label + 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) @@ -2498,10 +2468,7 @@ def export(componentObjs, fullfilePathName, scale=None, label=None): 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: @@ -2613,12 +2580,11 @@ def export(componentObjs, fullfilePathName, scale=None, label=None): # colors less then faces if len(single_color) != len(shape1.Faces): applyDiffuse = 0 - # copy color to all faces + # copy color to all faces # else copy singular colors for faces else: applyDiffuse = 1 - for color in single_color: - color_vector.append(color) + color_vector.extend(single_color) # say("color_vector") # say(color_vector) for index in range(len(shape1.Faces)): @@ -2628,26 +2594,10 @@ def export(componentObjs, fullfilePathName, scale=None, label=None): if exportV: if applyDiffuse: # say(color_vector[indexColor]) - meshes.append( - shapeToMesh( - singleFace, - color_vector[indexColor], - transparency[i], - mesh_dev, - scale, - ) - ) + meshes.append(shapeToMesh(singleFace, color_vector[indexColor], transparency[i], mesh_dev, scale)) else: # say(single_color[0]) - meshes.append( - shapeToMesh( - singleFace, - single_color[0], - transparency[i], - mesh_dev, - scale, - ) - ) + 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 = [] @@ -2873,10 +2823,10 @@ def group_part_union(): ] FreeCADGui.activeDocument().getObject(CopyName).Visibility = False FreeCADGui.ActiveDocument.getObject(FusionName).ShapeColor = FreeCADGui.ActiveDocument.getObject( - CopyName + CopyName, ).ShapeColor FreeCADGui.ActiveDocument.getObject(FusionName).DisplayMode = FreeCADGui.ActiveDocument.getObject( - CopyName + CopyName, ).DisplayMode FreeCAD.ActiveDocument.getObject(FusionName).Label = original_label + "_fd" FreeCAD.ActiveDocument.recompute() @@ -2948,10 +2898,10 @@ def group_part_union(): FreeCAD.activeDocument().getObject(FusionName).Shapes = objs FreeCADGui.activeDocument().getObject(CopyName).Visibility = False FreeCADGui.ActiveDocument.getObject(FusionName).ShapeColor = FreeCADGui.ActiveDocument.getObject( - CopyName + CopyName, ).ShapeColor FreeCADGui.ActiveDocument.getObject(FusionName).DisplayMode = FreeCADGui.ActiveDocument.getObject( - CopyName + CopyName, ).DisplayMode FreeCAD.ActiveDocument.getObject(FusionName).Label = original_label + "_fd" FreeCAD.ActiveDocument.recompute() @@ -3090,7 +3040,7 @@ def align_colors_to_materials(objects): single_color = FreeCADGui.ActiveDocument.getObject(obj.Name).DiffuseColor if len(single_color) != len(shape1.Faces): applyDiffuse = 0 - # copy color to all faces + # copy color to all faces # else copy singular colors for faces else: applyDiffuse = 1 @@ -3172,7 +3122,9 @@ def exportStep(objs, ffPathName): ## evaluate to modify reset placement base_shape = FreeCAD.ActiveDocument.getObject(objs[0].Name) if base_shape.Placement.Base != FreeCAD.Vector( - 0, 0, 0 + 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), @@ -3476,19 +3428,7 @@ def cfg_read_all(): 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_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 = [] @@ -3508,26 +3448,14 @@ def cfg_read_all(): 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 + 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") - if prefs.GetBool("asm3_links"): - links_imp_mode = "links_allowed" - else: - links_imp_mode = "links_not_allowed" - if prefs.GetBool("asm3_linkGroups"): - pass - else: - pass + 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 @@ -3831,7 +3759,6 @@ def reset_prop_shapes(obj, doc, App, Gui, rmv=None): # - ### def reset_prop_shapes2(obj, doc, App, Gui): @@ -3867,7 +3794,6 @@ def reset_prop_shapes2(obj, doc, App, Gui): # - ### def copy_objs(obj, doc): @@ -3975,7 +3901,7 @@ def createScaledBBox(name, scale): 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) + # 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, @@ -4035,24 +3961,10 @@ def Display_info(blacklisted_models): 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" - ) + msg += "
    Board Placed @ " + f"{board_base_point_x:.2f}" + ";" + f"{board_base_point_y:.2f}" + ";0.0" else: 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}" - + ")" - ) + 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: @@ -4095,24 +4007,10 @@ def Display_info(blacklisted_models): 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" - ) + say("Board Placed @ " + f"{board_base_point_x:.2f}" + ";" + f"{board_base_point_y:.2f}" + ";0.0") else: 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("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}" @@ -4120,7 +4018,7 @@ def Display_info(blacklisted_models): + f"{pcb_bbx.YLength:.2f}" + ";" + f"{pcb_bbx.ZLength:.2f}" - + ")" + + ")", ) if missingHeight: sayerr("MISSING pcb height from stack; forced 1.6mm value") @@ -4141,7 +4039,11 @@ def Display_info(blacklisted_models): 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 not in {"App::Line", "App::Plane", "App::Origin", "App::Part"} and "Local_CS" not in obj.Name + "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) @@ -4222,9 +4124,8 @@ def checkFCbug(fcv): # 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 + if hasattr(Part, "OCC_VERSION") and (Part.OCC_VERSION == "7.2.0"): + return True return False @@ -4267,7 +4168,10 @@ def Export2MCAD(blacklisted_model_elements): 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 not in {"App::Line", "App::Plane", "App::Origin", "App::Part", "Sketcher::SketchObject"} + "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) @@ -4398,7 +4302,7 @@ def Export2MCAD(blacklisted_model_elements): sayerr( "to export STEP it is necessary to use StepUp Workbench
    instead of the single Macro
    (because of " + str(fcv) - + " FC bug)" + + " FC bug)", ) msg = ( """to export STEP it is necessary to use StepUp Workbench
    instead of the single Macro
    (because of """ @@ -4410,10 +4314,7 @@ def Export2MCAD(blacklisted_model_elements): say("including sketch in grp") FreeCAD.ActiveDocument.getObject(sk[1]).addObject(FreeCAD.ActiveDocument.getObject(sk[0])) stop - if fcb: - cpmode = "compound" - else: - cpmode = "part" + cpmode = "compound" if fcb else "part" suffix = "_" to_export_name = kicadStepUpCMD.deep_copy(doc, cpmode, suffix) # to_export_name=FreeCAD.ActiveDocument.ActiveObject.Name @@ -4513,10 +4414,7 @@ def Export2MCAD(blacklisted_model_elements): 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 + 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") @@ -4556,24 +4454,10 @@ def Export2MCAD(blacklisted_model_elements): 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" - ) + msg += "
    Board Placed @ " + f"{board_base_point_x:.2f}" + ";" + f"{board_base_point_y:.2f}" + ";0.0" else: 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}" - + ")" - ) + 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: @@ -4599,24 +4483,10 @@ def Export2MCAD(blacklisted_model_elements): # 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" - ) + say("Board Placed @ " + f"{board_base_point_x:.2f}" + ";" + f"{board_base_point_y:.2f}" + ";0.0") else: 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("kicad pcb pos: (" + f"{real_board_pos_x:.2f}" + ";" + f"{real_board_pos_y:.2f}" + ";" + f"{0:.2f}" + ")") say_time() if show_messages: QtGui.QApplication.restoreOverrideCursor() @@ -4799,20 +4669,20 @@ def create_compound(count, modelnm): # create compound function when a multipar # stop modelnm_norm = make_string(modelnm) # to manage utf-8 FreeCAD.ActiveDocument.addObject("Part::Feature", modelnm_norm).Shape = FreeCAD.ActiveDocument.getObject( - mycompound.Name + mycompound.Name, ).Shape mynewObj = FreeCAD.ActiveDocument.ActiveObject FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject( - mycompound.Name + mycompound.Name, ).ShapeColor FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject( - mycompound.Name + mycompound.Name, ).LineColor FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject( - mycompound.Name + mycompound.Name, ).PointColor FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = FreeCADGui.ActiveDocument.getObject( - mycompound.Name + mycompound.Name, ).DiffuseColor ## if use_Links: # compound2 colors to be fixed ## FreeCADGui.ActiveDocument.ActiveObject.mapShapeColors(FreeCAD.ActiveDocument) @@ -4974,20 +4844,15 @@ def restore_specular(obj_pre_list): 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") @@ -5230,10 +5095,9 @@ def Load_models(pcbThickness, modules): 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 + if blacklisted_model_elements != "" and blacklisted_model_elements.find(model_name) != -1: + if model_name not in whitelisted_3Dmodels: + blacklisted = 1 ### if blacklisted == 0: @@ -5244,15 +5108,9 @@ def Load_models(pcbThickness, modules): 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) + 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, @@ -5360,7 +5218,7 @@ def Load_models(pcbThickness, modules): step_transparency = check_wrl_transparency(wrl_module_path) if step_transparency != 0: # keeping transparency if found in step file FreeCADGui.ActiveDocument.getObject( - myStep.Name + myStep.Name, ).Transparency = step_transparency impLabel = make_string(myStep.Label) # use_pypro=False @@ -5380,13 +5238,13 @@ def Load_models(pcbThickness, modules): else: myObj.Label = "REF_" + impLabel + "_" FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject( - newStep.Name + newStep.Name, ).ShapeColor FreeCADGui.ActiveDocument.ActiveObject.LineColor = FreeCADGui.ActiveDocument.getObject( - newStep.Name + newStep.Name, ).LineColor FreeCADGui.ActiveDocument.ActiveObject.PointColor = FreeCADGui.ActiveDocument.getObject( - newStep.Name + newStep.Name, ).PointColor FreeCADGui.ActiveDocument.ActiveObject.DiffuseColor = ( FreeCADGui.ActiveDocument.getObject(newStep.Name).DiffuseColor @@ -5402,10 +5260,7 @@ def Load_models(pcbThickness, modules): myTimeStamp = myTimeStamp[-12:] myModelNbr = modules[i][12] # print (myModelNbr)#;stop - if myModelNbr == 1: - myModelNbr = "" - else: - myModelNbr = "[" + str(myModelNbr) + "]" + myModelNbr = "" if myModelNbr == 1 else "[" + str(myModelNbr) + "]" if "*" not in myReference: newStep.Label = myReference + "_" + impLabel + "_" + myTimeStamp + myModelNbr else: @@ -5478,7 +5333,7 @@ def Load_models(pcbThickness, modules): "height > Min height " + str(newobj.Shape.BoundBox.ZLength) + " " - + newobj.Label + + newobj.Label, ) if volume_minimum != 0: say("Volume > Min Volume " + str(newobj.Shape.Volume) + " " + newobj.Label) @@ -5488,7 +5343,7 @@ def Load_models(pcbThickness, modules): "height <= Min height " + str(newobj.Shape.BoundBox.ZLength) + " " - + newobj.Label + + newobj.Label, ) else: skip_status = "skip" @@ -5496,7 +5351,7 @@ def Load_models(pcbThickness, modules): "Volume <= Min Volume " + str(newobj.Shape.BoundBox.ZLength) + " " - + newobj.Label + + newobj.Label, ) loaded_models_skipped.append(skip_status) use_cache = 0 @@ -5538,10 +5393,7 @@ def Load_models(pcbThickness, modules): # 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 + md_hide = bool(isHidden) # if show_debug: # sayw(wrl_rot) @@ -5575,11 +5427,13 @@ def Load_models(pcbThickness, modules): if use_pypro: FreeCAD.ActiveDocument.addObject("App::LinkPython", o.Label).setLink(o) FreeCAD.ActiveDocument.ActiveObject.addProperty( - "App::PropertyString", "TimeStamp" + "App::PropertyString", + "TimeStamp", ) # FreeCAD.ActiveDocument.ActiveObject.TimeStamp=str(modules[i][10]) FreeCAD.ActiveDocument.ActiveObject.addProperty( - "App::PropertyString", "Reference" + "App::PropertyString", + "Reference", ) # FreeCAD.ActiveDocument.ActiveObject.Reference=str(modules[i][11]) FreeCAD.ActiveDocument.ActiveObject.ViewObject.Proxy = 0 @@ -5610,10 +5464,7 @@ def Load_models(pcbThickness, modules): myReference = str(modules[i][11]).rstrip('"').lstrip('"') myModelNbr = modules[i][12] # print (myModelNbr);stop - if myModelNbr == 1: - myModelNbr = "" - else: - myModelNbr = "[" + str(myModelNbr) + "]" + 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[ @@ -5694,11 +5545,7 @@ def Load_models(pcbThickness, modules): 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]), - ), + 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) @@ -5707,11 +5554,7 @@ def Load_models(pcbThickness, modules): else: shape = impPart.Shape.copy() shape.Placement = impPart.Placement - shape.rotate( - (pos_x, pos_y, 0), - (0, 0, 1), - rot + float(wrl_rot[2]), - ) + shape.rotate((pos_x, pos_y, 0), (0, 0, 1), rot + float(wrl_rot[2])) impPart.Placement = shape.Placement ##TBChecked if force_transparency: @@ -5776,22 +5619,14 @@ def Load_models(pcbThickness, modules): 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]), - ), + 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]), - ) + 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) @@ -5907,19 +5742,11 @@ def Load_models(pcbThickness, modules): 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]), - ), + 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]), - ) + 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 @@ -5957,19 +5784,11 @@ def Load_models(pcbThickness, modules): 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]), - ), + 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]), - ) + 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 @@ -6037,7 +5856,7 @@ def Load_models(pcbThickness, modules): if virtualBot_nbr == 0: # FreeCAD.ActiveDocument.getObject("BotV").removeObjectsFromDocument() FreeCAD.ActiveDocument.removeObject(botV_name) - # FreeCAD.ActiveDocument.recompute() + # FreeCAD.ActiveDocument.recompute() if use_AppPart: if modelTop_nbr == 0: # FreeCAD.ActiveDocument.getObject("Top").removeObjectsFromDocument() @@ -6052,7 +5871,6 @@ def Load_models(pcbThickness, modules): if 0: # try print("TreeView Test collapsing") FreeCADGui.Selection.addSelection(FreeCAD.ActiveDocument.Board) - FreeCADGui.runCommand("ksuToolsToggleTreeView", 0) s = FreeCADGui.Selection.getSelection()[0] print(s.Label) @@ -6151,10 +5969,7 @@ def getPads(board_elab, pcbThickness): [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) + ROT = 0.0 if ROT == "" else float(ROT) # say('module pos & rot '+str(X1)+' '+str(Y1)+' '+str(ROT)) # for pad in getPadsList(module): @@ -6219,10 +6034,7 @@ def getPads_flat(board_elab): [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) + ROT = 0.0 if ROT == "" else float(ROT) # say('module pos & rot '+str(X1)+' '+str(Y1)+' '+str(ROT)) # for pad in getPadsList(module): @@ -6293,10 +6105,11 @@ def Elaborate_Kicad_Board(filename): 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) if ignore_utf8: content = re.sub(r"[^\x00-\x7F]+", " ", data) # workaround to remove utf8 extra chars @@ -6311,9 +6124,8 @@ def Elaborate_Kicad_Board(filename): 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 + 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) @@ -6378,9 +6190,8 @@ def Elaborate_Kicad_Board(filename): 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 + 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 @@ -6420,10 +6231,7 @@ def get3DParams(mdl_name, params, rot, virtual): # say("rotate vrml: "+rotz) else: rotz_vrml_m = "(xyz 0 0 0" - if rotz == "": - rotz = 0.0 - else: - rotz = float(rotz) + 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) @@ -6476,7 +6284,7 @@ def get3DParams(mdl_name, params, rot, virtual): # sayw("here") else: model_name = "no3Dmodel" - # sayerr('no3Dmodel') + # sayerr('no3Dmodel') return model_name, rot_comb, warn, pos_vrml, rotz_vrml, scale_vrml @@ -6809,7 +6617,6 @@ def onLoadFootprint(file_name=None): name = file_name elif not test_flag: # if test_flag==False: - Filter = "" ##if _platform == "darwin": ## ##workaround for OSX not opening native fileopen ## name=QtGui.QFileDialog.getOpenFileName(self, 'Open file', @@ -6822,14 +6629,17 @@ def onLoadFootprint(file_name=None): # path = FreeCAD.ConfigGet("UserAppData") # path=last_file_path # try: - # name, Filter = PySide.QtGui.QFileDialog.getOpenFileName(None, "Open File", last_file_path, "*.kicad_mod")#PySide + # 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" + name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( + None, + "Open File...", + make_unicode(last_fp_path), + "*.kicad_mod", ) else: name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( @@ -6907,15 +6717,13 @@ def onLoadFootprint(file_name=None): 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") + 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() @@ -6942,19 +6750,16 @@ def check_requirements(): 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() - QtGui.QMessageBox.information(None, "Warning! ...", msg1) + 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: - if FC_git_Nbr >= int(FC_export_min_version): - use_AppPart = True + 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 + 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: @@ -6986,11 +6791,10 @@ def sanitizeSketch(s_name): 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") - idx_to_del.append(i) + 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 @@ -7064,10 +6868,7 @@ def add_constraints(s_name): # 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" + 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]) @@ -7247,42 +7048,22 @@ def add_missing_geo(s_name): 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), - ) - ) + 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), - ) - ) + 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), - ) - ) + 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), - ) - ) + 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") @@ -7542,8 +7323,6 @@ def onLoadBoard(file_name=None, load_models=None, insert=None): # export_board_2step=True #for cmd line force exporting to STEP name = file_name elif not test_flag: - Filter = "" - # minimize main window # self.setWindowState(QtCore.Qt.WindowMinimized) # infoDialog('ciao') # reply = QtGui.QInputDialog.getText(None, "Hello","Enter your thoughts for the day:") @@ -7557,7 +7336,7 @@ def onLoadBoard(file_name=None, load_models=None, insert=None): # 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( + name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( None, "Open kicad PCB File...", make_unicode(last_pcb_path), @@ -7723,10 +7502,7 @@ def onLoadBoard(file_name=None, load_models=None, insert=None): ) 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 @@ -7867,12 +7643,10 @@ def onLoadBoard(file_name=None, load_models=None, insert=None): ##FreeCAD.ActiveDocument.recompute() pcb_sk = FreeCAD.ActiveDocument.getObject(newname) - gi = 0 - for g in pcb_sk.Geometry: + 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), @@ -7914,10 +7688,9 @@ def onLoadBoard(file_name=None, load_models=None, insert=None): # objs_toberemoved.append([doc.getObject(sketch_name_sfx+'001')]) docG = FreeCADGui.ActiveDocument docG.getObject(sketch_name_sfx).Visibility = True - elif override_pcb: - if doc.getObject(sketch_name_sfx) in doc.Objects: # if 1: #try: - docG = FreeCADGui.ActiveDocument - 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") @@ -7986,27 +7759,45 @@ def onLoadBoard(file_name=None, load_models=None, insert=None): 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(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(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(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(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(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(stepV_name), + doc.getObject(stepV_name), + "", + [], ) FreeCADGui.Selection.clearSelection() else: @@ -8038,12 +7829,11 @@ def onLoadBoard(file_name=None, load_models=None, insert=None): 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") @@ -8052,11 +7842,8 @@ def onLoadBoard(file_name=None, load_models=None, insert=None): # 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") + 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) @@ -8082,15 +7869,13 @@ def onLoadBoard(file_name=None, load_models=None, insert=None): paramGetVS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Import/hSTEP") 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) @@ -8191,36 +7976,41 @@ def find_nth(haystack, needle, n): 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 "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) + 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): # FreeCADGui.Selection.clearSelection() @@ -8272,10 +8062,9 @@ def removing_kobjs(): 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") + if False: + if "PartWorkbench" not in FreeCADGui.activeWorkbench().name(): + FreeCADGui.activateWorkbench("PartWorkbench") # FreeCADGui.SendMsgToActiveView("ViewFit") ##FreeCADGui.activeDocument().activeView().viewTop() doc = FreeCAD.ActiveDocument @@ -8308,33 +8097,21 @@ def routineR_XYZ(axe, 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, - ), + (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, - ), + (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, - ), + (oripl_X + boundBoxLX / 2, oripl_Y + boundBoxLY / 2, oripl_Z + boundBoxLZ / 2), (0, 0, 1), int(angle), ) @@ -8359,10 +8136,9 @@ def routineR_XYZ(axe, alpha): 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") + if False: + if "PartWorkbench" not in FreeCADGui.activeWorkbench().name(): + FreeCADGui.activateWorkbench("PartWorkbench") # FreeCADGui.SendMsgToActiveView("ViewFit") ##FreeCADGui.activeDocument().activeView().viewTop() doc = FreeCAD.ActiveDocument @@ -8410,11 +8186,9 @@ def routineT_XYZ(axe, v): 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") + if False: + if "PartWorkbench" not in FreeCADGui.activeWorkbench().name() and keepWB is None: + FreeCADGui.activateWorkbench("PartWorkbench") # FreeCADGui.SendMsgToActiveView("ViewFit") ##FreeCADGui.activeDocument().activeView().viewTop() selEx = FreeCADGui.Selection.getSelectionEx() @@ -8447,7 +8221,7 @@ def routineResetPlacement(keepWB=None): 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 + objs[0].Name, ) RefName = FreeCAD.ActiveDocument.ActiveObject.Name FreeCAD.ActiveDocument.recompute() @@ -8464,19 +8238,19 @@ def routineResetPlacement(keepWB=None): if hasattr(FreeCADGui.ActiveDocument.getObject(objs[0].Name), "ShapeColor"): say("has shapecolor") FreeCADGui.ActiveDocument.getObject(CpyName).ShapeColor = FreeCADGui.ActiveDocument.getObject( - objs[0].Name + objs[0].Name, ).ShapeColor FreeCADGui.ActiveDocument.getObject(CpyName).LineColor = FreeCADGui.ActiveDocument.getObject( - objs[0].Name + objs[0].Name, ).LineColor FreeCADGui.ActiveDocument.getObject(CpyName).PointColor = FreeCADGui.ActiveDocument.getObject( - objs[0].Name + objs[0].Name, ).PointColor FreeCADGui.ActiveDocument.getObject(CpyName).DiffuseColor = FreeCADGui.ActiveDocument.getObject( - objs[0].Name + objs[0].Name, ).DiffuseColor FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject( - objs[0].Name + objs[0].Name, ).Transparency new_label = objs[0].Label @@ -8602,10 +8376,9 @@ def routineScaleVRML(): 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") + if False: + if "PartWorkbench" not in FreeCADGui.activeWorkbench().name(): + FreeCADGui.activateWorkbench("PartWorkbench") # FreeCADGui.SendMsgToActiveView("ViewFit") ##FreeCADGui.activeDocument().activeView().viewTop() selEx = FreeCADGui.Selection.getSelectionEx() @@ -8675,10 +8448,9 @@ def routineC_XYZ(axe): 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") + if False: + if "PartWorkbench" not in FreeCADGui.activeWorkbench().name(): + FreeCADGui.activateWorkbench("PartWorkbench") # FreeCADGui.SendMsgToActiveView("ViewFit") ##FreeCADGui.activeDocument().activeView().viewTop() doc = FreeCAD.ActiveDocument @@ -8752,10 +8524,9 @@ 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") + if False: + if "PartWorkbench" not in FreeCADGui.activeWorkbench().name(): + FreeCADGui.activateWorkbench("PartWorkbench") # FreeCADGui.SendMsgToActiveView("ViewFit") ##FreeCADGui.activeDocument().activeView().viewTop() doc = FreeCAD.ActiveDocument @@ -8885,10 +8656,9 @@ def say_info(msg): 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") + if False: + if "PartWorkbench" not in FreeCADGui.activeWorkbench().name(): + FreeCADGui.activateWorkbench("PartWorkbench") # FreeCADGui.SendMsgToActiveView("ViewFit") ##FreeCADGui.activeDocument().activeView().viewTop() # say("hereXYZ !") @@ -8926,20 +8696,20 @@ def get_position(): 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_() + ##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 @@ -8948,10 +8718,9 @@ def get_position(): def routineM_XYZ(axe, v): global resetP 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") + if False: + if "PartWorkbench" not in FreeCADGui.activeWorkbench().name(): + FreeCADGui.activateWorkbench("PartWorkbench") # FreeCADGui.SendMsgToActiveView("ViewFit") ##FreeCADGui.activeDocument().activeView().viewTop() doc = FreeCAD.ActiveDocument @@ -9059,12 +8828,11 @@ def error_dialog(msg): ): # 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 + 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') @@ -9107,11 +8875,7 @@ def error_dialog(msg): # print object_a.InListRecursive # print object_b.InListRecursive ## copy objects and apply absolute placement to each one, then check collisions - FreeCAD.Placement( - FreeCAD.Vector(0, 0, 0), - FreeCAD.Rotation(0, 0, 0), - FreeCAD.Vector(0, 0, 0), - ) + 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 = [] @@ -9139,7 +8903,7 @@ def error_dialog(msg): for i in range(lrl): if hasattr(object_a.InListRecursive[i], "Placement"): acpy.Placement = acpy.Placement.multiply( - object_a.InListRecursive[lrl - 1 - i].Placement + object_a.InListRecursive[lrl - 1 - i].Placement, ) # acpy.Placement=acpy.Placement.multiply(pa_Original) # Part.show(acpy) @@ -9166,7 +8930,7 @@ def error_dialog(msg): for i in range(lrl): if hasattr(object_b.InListRecursive[i], "Placement"): bcpy.Placement = bcpy.Placement.multiply( - object_b.InListRecursive[lrl - 1 - i].Placement + object_b.InListRecursive[lrl - 1 - i].Placement, ) # Part.show(bcpy) common = acpy.common(bcpy) @@ -9297,22 +9061,16 @@ def create_axis(): 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.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.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, @@ -9349,22 +9107,16 @@ def create_axis(): 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.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.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, @@ -9387,7 +9139,8 @@ def create_axis(): 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.Vector(0, 0, 0.05), + FreeCAD.Rotation(FreeCAD.Vector(1, 0, 0), -90), ) # X axis @@ -9404,22 +9157,16 @@ def create_axis(): 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.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.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, @@ -9441,14 +9188,14 @@ def create_axis(): 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.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") ### @@ -9518,13 +9265,7 @@ def rotateObj(mainObj, rot): ### 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, - ) + Draft.rotate(listObjs, rot[2], FreeCAD.Vector(rot[0], rot[1], 0.0), axis=FreeCAD.Vector(0.0, 0.0, 1.0), copy=False) ### @@ -9548,11 +9289,7 @@ def arcMidPoint(prev_vertex, vertex, angle): 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) - return [ - (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)] ### @@ -9634,7 +9371,6 @@ def arcRadius(x1, y1, x2, y2, angle): 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): # sa = atan2 (ys-cy, xs-cx) @@ -9781,10 +9517,7 @@ 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]) # @@ -9812,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: @@ -9865,10 +9595,7 @@ def getArc(layer, content, oType): 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 if abs(curve) == 360: [x2, y2] = [xs, ys] else: @@ -9889,10 +9616,7 @@ 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 @@ -9913,10 +9637,7 @@ def getArcF(layer, content, oType, m=[0, 0]): 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 @@ -10013,10 +9734,7 @@ 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) + zrot_vrml = 0.0 if zrot_vrml == "" else float(zrot_vrml) # say(rot_wrl); return wrl_pos, scale_vrml, rot_wrl @@ -10038,11 +9756,7 @@ def getwrlRot(source): # say("rotz temp:"+temp[2]) rotz = temp[2] # say("rotate vrml: "+rotz) - if rotz == "": - rotz = 0.0 - else: - rotz = float(rotz) - return rotz # adding vrml module z-rotation + return 0.0 if rotz == "" else float(rotz) ### @@ -10078,13 +9792,11 @@ def getPadsList(content): 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 + 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 + 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: @@ -10105,10 +9817,7 @@ def getPadsList(content): 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 = 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) @@ -10140,15 +9849,9 @@ 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] @@ -10162,15 +9865,9 @@ def getPadsList(content): 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( @@ -10192,7 +9889,7 @@ def getPadsList(content): "anchor": anchor, "rratio": pRound, "geomC": pCircleG, - } + }, ) # say(pads) @@ -10310,7 +10007,7 @@ def createArc_OLD(p1, p2, curve, width=0.02, cap="round"): 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) @@ -10319,22 +10016,12 @@ def createArc_OLD(p1, p2, curve, width=0.02, cap="round"): 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": - 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))) @@ -10378,7 +10065,7 @@ def createArc_OLD(p1, p2, curve, width=0.02, cap="round"): 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 @@ -10409,7 +10096,7 @@ def createArc_OLD(p1, p2, curve, width=0.02, cap="round"): FreeCAD.Base.Vector(xT_2, yT_2, 0), FreeCAD.Base.Vector(xT_8, yT_8, 0), FreeCAD.Base.Vector(xT_5, yT_5, 0), - ) + ), ) #### @@ -10450,8 +10137,8 @@ def createArc(p1, p2, curve, width=0.02, cap="round"): 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 @@ -10462,28 +10149,14 @@ def createArc(p1, p2, curve, width=0.02, cap="round"): 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": - 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), - ) - ) - ) + 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))) else: @@ -10530,8 +10203,8 @@ def createArc(p1, p2, curve, width=0.02, cap="round"): 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))) @@ -10564,8 +10237,8 @@ def createArc(p1, p2, curve, width=0.02, cap="round"): 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))) @@ -10620,10 +10293,7 @@ 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 @@ -10649,8 +10319,8 @@ def createLine(x1, y1, x2, y2, width=0.01): 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))) @@ -10663,8 +10333,8 @@ def createLine(x1, y1, x2, y2, width=0.01): 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) @@ -10702,10 +10372,7 @@ def addPadLong2(x, y, dx, dy, perc, typ, z_off, type=None, ratio=None): if typ == 0: # % if perc > 100.0: perc == 100.0 - if dx > dy: - e = dy * perc / 100.0 - else: - e = dx * 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: @@ -10722,12 +10389,7 @@ def addPadLong2(x, y, dx, dy, perc, typ, z_off, type=None, ratio=None): 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), - ) - ) + 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( @@ -10735,15 +10397,10 @@ def addPadLong2(x, y, dx, dy, perc, typ, z_off, type=None, ratio=None): 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), - ) - ) + 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( @@ -10751,15 +10408,10 @@ def addPadLong2(x, y, dx, dy, perc, typ, z_off, type=None, ratio=None): 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), - ) - ) + 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( @@ -10767,15 +10419,10 @@ def addPadLong2(x, y, dx, dy, perc, typ, z_off, type=None, ratio=None): 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), - ) - ) + 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( @@ -10783,7 +10430,7 @@ def addPadLong2(x, y, dx, dy, perc, typ, z_off, type=None, ratio=None): 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" @@ -10822,10 +10469,7 @@ def addPadLong(x, y, dx, dy, perc, typ, z_off): if typ == 0: # % if perc > 100.0: perc == 100.0 - if dx > dy: - e = dy * perc / 100.0 - else: - e = dx * 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] @@ -10838,12 +10482,7 @@ def addPadLong(x, y, dx, dy, perc, typ, 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), - ) - ) + 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( @@ -10851,15 +10490,10 @@ def addPadLong(x, y, dx, dy, perc, typ, z_off): 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), - ) - ) + 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( @@ -10867,15 +10501,10 @@ def addPadLong(x, y, dx, dy, perc, typ, z_off): 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), - ) - ) + 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( @@ -10883,15 +10512,10 @@ def addPadLong(x, y, dx, dy, perc, typ, z_off): 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), - ) - ) + 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( @@ -10899,7 +10523,7 @@ def addPadLong(x, y, dx, dy, perc, typ, z_off): 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" @@ -10943,10 +10567,7 @@ def createPad2(x, y, sx, sy, dcx, dcy, dx, dy, type, layer): else: perc = 0 tp = 0 - if layer == "top": - z_offset = 0 - else: - z_offset = -1.6 + 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) @@ -11062,20 +10683,12 @@ def createPad(x, y, sx, sy, dcx, dcy, dx, dy, type, layer): 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.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) + 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) @@ -11089,11 +10702,7 @@ def createPad(x, y, sx, sy, dcx, dcy, dx, dy, type, layer): 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) + 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() @@ -11163,7 +10772,7 @@ def createPad3(x, y, sx, sy, dcx, dcy, dx, dy, type, layer, ratio=None): ### -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 @@ -11223,20 +10832,12 @@ def createPad(x, y, sx, sy, dcx, dcy, dx, dy, type, layer): 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.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) + 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) @@ -11250,11 +10851,7 @@ def createPad(x, y, sx, sy, dcx, dcy, dx, dy, type, layer): 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) + 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() @@ -11287,7 +10884,7 @@ def createHole(x, y, dx, dy, type): hole_name = "hole" FreeCAD.ActiveDocument.addObject("Part::Feature", hole_name).Shape = FreeCAD.ActiveDocument.getObject( - extrude_hole_name + extrude_hole_name, ).Shape FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = (0.67, 1.00, 0.50) FreeCADGui.ActiveDocument.ActiveObject.Transparency = 70 @@ -11345,7 +10942,6 @@ def createHole3(x, y, dx, dy, type, height): # FreeCAD.ActiveDocument.recompute() - ### ### def createHole4(x, y, dx, dy, type): @@ -11409,7 +11005,6 @@ def createTHPlate(x, y, dx, dy, type): # FreeCAD.ActiveDocument.recompute() - ### def createGeomC(cx, cy, radius, layer, width): # createGeomC(Gcx, Gcy, GRad,'top', Gw) @@ -11622,10 +11217,7 @@ def routineDrawFootPrint(content, name): 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 = FreeCAD.activeDocument() if FreeCAD.activeDocument() else FreeCAD.newDocument() # doc.UndoMode = 1 # doc.openTransaction() doc.openTransaction("opening_kicad_footprint") @@ -11845,15 +11437,7 @@ def routineDrawFootPrint(content, name): BCrtYd = [] BFab = [] - layer_names = [ - "F.SilkS", - "F.CrtYd", - "F.Fab", - "Edge.Cuts", - "B.SilkS", - "B.CrtYd", - "B.Fab", - ] + 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) @@ -12069,11 +11653,7 @@ def routineDrawFootPrint(content, name): 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) + 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) @@ -12087,11 +11667,7 @@ def routineDrawFootPrint(content, name): 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) + 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") @@ -12101,11 +11677,7 @@ def routineDrawFootPrint(content, name): 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") @@ -12117,11 +11689,7 @@ def routineDrawFootPrint(content, name): 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) + 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: Holes = Part.makeCompound(HoleList) @@ -12273,11 +11841,7 @@ def routineDrawFootPrint(content, name): cut_base = cut_base.cut(holes.Shape) Part.show(cut_base) 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 @@ -12292,11 +11856,7 @@ def routineDrawFootPrint(content, name): cut_base = cut_base.cut(holes.Shape) Part.show(cut_base) 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 @@ -12312,11 +11872,7 @@ def routineDrawFootPrint(content, name): cut_base = cut_base.cut(holes.Shape) Part.show(cut_base) 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 @@ -12331,11 +11887,7 @@ def routineDrawFootPrint(content, name): cut_base = cut_base.cut(holes.Shape) Part.show(cut_base) 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 @@ -12465,7 +12017,7 @@ def routineDrawIDF(doc, filename): float(emnrecords[1]) * emn_unit, float(emnrecords[2]) * emn_unit, float(emnrecords[3]), - ] + ], ) if ( current_section == ".DRILLED_HOLES" @@ -12473,11 +12025,7 @@ def routineDrawIDF(doc, filename): 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, - ] + [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 = [] @@ -12684,8 +12232,6 @@ def joint(point): return result[1] - - def distance(p0, p1): return sqrt((p0[0] - p1[0]) ** 2 + (p0[1] - p1[1]) ** 2) @@ -12738,16 +12284,19 @@ def builddepdict(self): for bigfacei, smallfacei in itertools.combinations(range(len(self.sortedfaces)), 2): try: overlap = OSCD2Dg_Overlappingfaces.dofacesoverlapproximity( - self.sortedfaces[bigfacei], self.sortedfaces[smallfacei] + self.sortedfaces[bigfacei], + self.sortedfaces[smallfacei], ) except (NotImplementedError, Part.OCCError): try: overlap = OSCD2Dg_Overlappingfaces.dofacesoverlapboolean( - self.sortedfaces[bigfacei], self.sortedfaces[smallfacei] + self.sortedfaces[bigfacei], + self.sortedfaces[smallfacei], ) except Part.OCCError: overlap = OSCD2Dg_Overlappingfaces.dofacesoverlapallverts( - self.sortedfaces[bigfacei], self.sortedfaces[smallfacei] + self.sortedfaces[bigfacei], + self.sortedfaces[smallfacei], ) if overlap: # isinsidelist.append((bigfacei,smallfacei)) @@ -12762,7 +12311,7 @@ def finddepth(dict1, faceidx, curdepth=0): 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]] + [(OSCD2Dg_Overlappingfaces.finddepth(dict1, childface, curdepth + 1)) for childface in dict1[faceidx]], ) def findrootdepth(self): @@ -12788,7 +12337,6 @@ def directchildren(isinsidedict, parent): dchildren = [] for child in isinsidedict.get(parent, []): direct = True - py2 = False if py2: for key, value in isinsidedict.iteritems(): @@ -12822,9 +12370,8 @@ def printtreechild(isinsidedict, facenum, parent): printtreechild(isinsidedict, facenum, rootitem) 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 @@ -12836,7 +12383,7 @@ def addfeature(faceindex, isinsidedict): else: subdict = isinsidedict.copy() del subdict[faceindex] - obj = doc.addObject("Part::Cut", "facesfromedges_%d" % faceindex) + 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) @@ -12919,55 +12466,36 @@ def median(v1, v2): 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 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 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 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 # 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): + 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"): - if isinstance(curr[0].Curve, Part.Line): - # print "line",p1,p2 - newedges.append(Part.Line(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 @@ -13193,8 +12721,6 @@ def OSCD2Dg_edgestofaces(edges, algo=3, eps=0.001): return None - - ### def get_mod_Ref(m): # if hasattr(m,'property'): @@ -13255,10 +12781,7 @@ def simu_distance(p0, p1): edges = [] PCBs = [] # print (mypcb.general) #maui errorchecking - if hasattr(mypcb, "general"): - totalHeight = float(mypcb.general.thickness) - else: - totalHeight = 1.6 + totalHeight = float(mypcb.general.thickness) if hasattr(mypcb, "general") else 1.6 missingHeight = False if totalHeight == 0: totalHeight = 1.6 @@ -13313,10 +12836,7 @@ def simu_distance(p0, p1): # print(lyr) for ln in mypcb.gr_line: - if hasattr(ln, "layer"): - k_test = ln.layer - else: - k_test = 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) @@ -13324,10 +12844,7 @@ def simu_distance(p0, p1): # 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 @@ -13335,10 +12852,7 @@ def simu_distance(p0, p1): # print(lp) # print(lp.layer) # print(lp.pts) - if hasattr(lp, "layer"): - k_test = lp.layer - else: - k_test = lp.layers + k_test = lp.layer if hasattr(lp, "layer") else lp.layers if lyr in k_test: # sayerr(lp.layer) try: @@ -13351,20 +12865,14 @@ def simu_distance(p0, p1): # 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) for p in bs.pts.xy: 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 @@ -13412,14 +12920,13 @@ def simu_distance(p0, p1): if float(lynbr) == Top_lvl: LvlTopName = mypcb.layers[f"{str(lynbr)}"][0] if float(lynbr) == Edge_Cuts_lvl: - mypcb.layers[f"{str(lynbr)}"][0] + (mypcb.layers[f"{str(lynbr)}"][0]) else: LvlTopName = "F.Cu" # # sayerr(lyr[0]) # # sayerr('top') - if hasattr(mypcb, "general"): - if hasattr(mypcb.general, "area"): - say("board area " + str(mypcb.general.area)) + 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 @@ -13506,12 +13013,7 @@ def make_gr_line_obj(l, add_ply=None): 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), - ) - ) + 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: @@ -13521,16 +13023,11 @@ def make_gr_line_obj(l, add_ply=None): 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), - ) - ) + 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: @@ -13538,10 +13035,7 @@ def make_gr_line_obj(l, add_ply=None): 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 + 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))) @@ -13551,112 +13045,69 @@ def make_gr_line_obj(l, add_ply=None): 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 + 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), - ) - ) + 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), - ) + ), ) else: - PCB_Geo.append( - PLine( - Base.Vector(r.start[0], -r.start[1], 0), - Base.Vector(r.end[0], -r.start[1], 0), - ) - ) + 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), - ) - ) + 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), - ) + ), ) else: - PCB_Geo.append( - PLine( - Base.Vector(r.end[0], -r.start[1], 0), - Base.Vector(r.end[0], -r.end[1], 0), - ) - ) + 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), - ) - ) + 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), - ) + ), ) else: - PCB_Geo.append( - PLine( - Base.Vector(r.end[0], -r.end[1], 0), - Base.Vector(r.start[0], -r.end[1], 0), - ) - ) + 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), - ) - ) + 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), - ) + ), ) else: - PCB_Geo.append( - PLine( - Base.Vector(r.start[0], -r.end[1], 0), - Base.Vector(r.start[0], -r.start[1], 0), - ) - ) + 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: @@ -13690,16 +13141,15 @@ def make_gr_line_obj(l, add_ply=None): continue elif not hasattr(zn, "keepout"): continue - ind = 0 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) if load_sketch: @@ -13712,12 +13162,8 @@ def make_gr_line_obj(l, add_ply=None): -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, - ), - ) + Base.Vector(zn.polygon.pts.xy[0][0] - off_x, -zn.polygon.pts.xy[0][1] - off_y, 0), + ), ) line2 = Part.Edge( PLine( @@ -13726,46 +13172,30 @@ def make_gr_line_obj(l, add_ply=None): -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, - ), - ) + 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[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[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 - 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: @@ -13778,12 +13208,8 @@ def make_gr_line_obj(l, add_ply=None): -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, - ), - ) + Base.Vector(zn.polygon.pts.xy[ind][0] - off_x, -zn.polygon.pts.xy[ind][1] - off_y, 0), + ), ) line2 = Part.Edge( PLine( @@ -13792,45 +13218,24 @@ def make_gr_line_obj(l, add_ply=None): -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, - ), - ) + 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, - ), - ) + 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, - ), - ) + 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) @@ -13847,13 +13252,7 @@ def make_gr_arc_obj(a, pa): 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), - ) - ) + 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) @@ -13871,7 +13270,7 @@ def make_gr_arc_obj(a, pa): 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) @@ -13907,7 +13306,7 @@ def make_gr_arc_obj(a, pa): 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]), @@ -13928,14 +13327,10 @@ def make_gr_arc_obj(a, pa): else: PCB_Geo.append( Part.ArcOfCircle( - Part.Circle( - FreeCAD.Vector(cx - off_x, cy - off_y, 0), - FreeCAD.Vector(0, 0, 1), - r, - ), + 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( @@ -13943,28 +13338,19 @@ def make_gr_arc_obj(a, pa): kicad_parser.makeVect(a.start), kicad_parser.makeVect(a.mid), kicad_parser.makeVect(a.end), - ) + ), ) - if pa != "": - if 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) + 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: # 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, - ) + 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) @@ -13983,10 +13369,7 @@ def make_gr_arc_obj(a, pa): # k_index = 0 for lp in mypcb.gr_poly: # pcb polylines - if hasattr(lp, "layer"): - k_test = lp.layer - else: - k_test = lp.layers + k_test = lp.layer if hasattr(lp, "layer") else lp.layers if lyr not in k_test: # if lp.layer != 'Edge.Cuts': continue @@ -14000,7 +13383,7 @@ def make_gr_arc_obj(a, pa): 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: @@ -14008,32 +13391,16 @@ def make_gr_arc_obj(a, pa): # 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, - ), - ) + 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, - ), - ) + 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))) @@ -14041,14 +13408,14 @@ def make_gr_arc_obj(a, pa): 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) @@ -14057,7 +13424,7 @@ def make_gr_arc_obj(a, pa): 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: @@ -14065,32 +13432,16 @@ def make_gr_arc_obj(a, pa): # 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, - ), - ) + 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, - ), - ) + 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))) @@ -14098,18 +13449,14 @@ def make_gr_arc_obj(a, pa): 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 - 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) @@ -14141,10 +13488,7 @@ def make_gr_arc_obj(a, pa): # 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 @@ -14194,10 +13538,7 @@ def make_gr_arc_obj(a, pa): 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 @@ -14208,10 +13549,7 @@ def make_gr_arc_obj(a, pa): ## NB use always float() to guarantee number not string!!! 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 @@ -14226,13 +13564,7 @@ def make_gr_arc_obj(a, pa): 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, - ) - ) + 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)) @@ -14280,7 +13612,7 @@ def make_gr_arc_obj(a, pa): d.setText( """Warning: High number of entities to join (> """ + str(max_edges_admitted) - + """)
    Constraints will not be applied to PCB Sketch""" + + """)
    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) @@ -14316,10 +13648,7 @@ def make_gr_arc_obj(a, pa): # 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_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) @@ -14427,16 +13756,15 @@ def make_gr_arc_obj(a, pa): "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 + ) 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") @@ -14454,11 +13782,7 @@ def make_gr_arc_obj(a, pa): # 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, - ] + 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, @@ -14573,7 +13897,12 @@ def make_gr_arc_obj(a, pa): # sayw('holes solid '+str(holes_solid)) if holes_solid: obj = createHole3( - x1, y1, rx, ry, "oval", totalHeight + x1, + y1, + rx, + ry, + "oval", + totalHeight, ) # need to be separated instructions else: obj = createHole4(x1, y1, rx, ry, "oval") # need to be separated instructions @@ -14602,7 +13931,12 @@ def make_gr_arc_obj(a, pa): [x1, y1] = rotPoint2([xs, ys], [m.at[0], -m.at[1]], m_angle) if holes_solid: obj = createHole3( - x1, y1, rx, ry, "oval", totalHeight + x1, + y1, + rx, + ry, + "oval", + totalHeight, ) # need to be separated instructions else: obj = createHole4(x1, y1, rx, ry, "oval") # need to be separated instructions @@ -14644,7 +13978,7 @@ def make_gr_arc_obj(a, pa): 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: @@ -14652,7 +13986,7 @@ def make_gr_arc_obj(a, pa): 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 @@ -14669,10 +14003,7 @@ def make_gr_arc_obj(a, pa): [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), - ) + 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))) @@ -14696,7 +14027,12 @@ def make_gr_arc_obj(a, pa): ry = radius if holes_solid: obj = createHole3( - x1, y1, rx, ry, "oval", totalHeight + x1, + y1, + rx, + ry, + "oval", + totalHeight, ) # need to be separated instructions else: obj = createHole4(x1, y1, rx, ry, "oval") # need to be separated instructions @@ -14721,10 +14057,7 @@ def make_gr_arc_obj(a, pa): 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), - ) + 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))) @@ -14757,11 +14090,7 @@ def make_gr_arc_obj(a, pa): 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, - ) + 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)) @@ -14787,7 +14116,7 @@ def make_gr_arc_obj(a, pa): kicad_parser.makeVect(ma.start), kicad_parser.makeVect(ma.mid), kicad_parser.makeVect(ma.end), - ).toShape() + ).toShape(), ) arc1.rotate(Vector(), Vector(0, 0, 1), m_angle) if aux_orig == 1 or grid_orig == 1: @@ -14823,7 +14152,7 @@ def make_gr_arc_obj(a, pa): 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) @@ -14836,26 +14165,16 @@ def make_gr_arc_obj(a, pa): 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, - ), + 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, - ) + Part.Circle(FreeCAD.Vector(cx, cy, 0), FreeCAD.Vector(0, 0, 1), r), sa, ea + ), ) if show_border: Part.show(arc1) @@ -14895,17 +14214,16 @@ def make_gr_arc_obj(a, pa): say("start adding constraints to pcb sketch") get_time() t0 = running_time - if hasattr( - FreeCAD.ActiveDocument.getObject(PCB2Sketch.Name), - "autoconstraint", - ): + if hasattr(FreeCAD.ActiveDocument.getObject(PCB2Sketch.Name), "autoconstraint"): if addConstraints == "full": FreeCAD.ActiveDocument.getObject("PCB_Sketch_draft").autoconstraint( - edge_tolerance * 5, 0.01 + edge_tolerance * 5, + 0.01, ) if use_PCB_Sketch_E: FreeCAD.ActiveDocument.getObject("PCB_Sketch_draft_E").autoconstraint( - edge_tolerance * 5, 0.01 + edge_tolerance * 5, + 0.01, ) else: add_constraints("PCB_Sketch_draft") @@ -15127,7 +14445,7 @@ def make_gr_arc_obj(a, pa): "non coincident edges:\n" + str(nextCoordinate) + ";" - + str(edge.Vertexes[-1].Point) + + str(edge.Vertexes[-1].Point), ) nextCoordinate = edge.Vertexes[0].Point newEdges.append(edges.pop(j)) @@ -15138,10 +14456,7 @@ def make_gr_arc_obj(a, pa): # 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) + "non coincident edges:\n" + str(nextCoordinate) + ";" + str(edge.Vertexes[0].Point), ) nextCoordinate = edge.Vertexes[-1].Point newEdges.append(edges.pop(j)) @@ -15186,7 +14501,7 @@ def make_gr_arc_obj(a, pa): + str(nextCoordinate.x) + "mm, y=" + str(nextCoordinate.y) - + "mm ***" + + "mm ***", ) say("pcb edge not closed") QtGui.QApplication.restoreOverrideCursor() @@ -15637,9 +14952,7 @@ def addObject(shape, name="Shape", layer=None): # 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(_) @@ -15731,7 +15044,10 @@ def addObject(shape, name="Shape", layer=None): except: pass doc.getObject(board_name).ViewObject.dropObject( - doc.getObject(boardG_name), doc.getObject(boardG_name), "", [] + doc.getObject(boardG_name), + doc.getObject(boardG_name), + "", + [], ) else: try: @@ -15753,7 +15069,10 @@ def addObject(shape, name="Shape", layer=None): # 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), "", [] + doc.getObject(pcb_name), + doc.getObject(pcb_name), + "", + [], ) FreeCADGui.Selection.clearSelection() # FreeCADGui.activeView().setActiveObject('Board_Geoms', doc.Board_Geoms) @@ -15773,7 +15092,7 @@ def addObject(shape, name="Shape", layer=None): + f"{pcb_bbx.YLength:.2f}" + ";" + f"{pcb_bbx.ZLength:.2f}" - + ")" + + ")", ) say_time() if k_index == 1: @@ -15860,9 +15179,8 @@ def addObject(shape, name="Shape", layer=None): 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 + if hasattr(o, "Label") and o.Label.endswith("_fp"): + fp_loaded = True # say("opening "+ fullfilePath) # cfgParsWrite(configFilePath) # cfg_update_all() @@ -15914,12 +15232,8 @@ def addObject(shape, name="Shape", layer=None): class Ui_DockWidget: def link(self, linkStr): - # QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr)) - try: + with contextlib.suppress(Exception): QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr)) # workaround Qt5 waiting for PySide - except: - # QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr.fromLocalFile())) - pass # class Ui_DockWidget(object): def setupUi(self, DockWidget): @@ -15945,11 +15259,7 @@ def setupUi(self, DockWidget): 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, - ) + icon1.addPixmap(QtGui.QPixmap("icons-new/dock_left.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.dock_left.setIcon(icon1) self.dock_left.setIconSize(QtCore.QSize(24, 24)) self.dock_left.setObjectName("dock_left") @@ -15979,11 +15289,7 @@ def setupUi(self, DockWidget): 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, - ) + icon4.addPixmap(QtGui.QPixmap("icons-new/dock_right.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.dock_right.setIcon(icon4) self.dock_right.setIconSize(QtCore.QSize(24, 24)) self.dock_right.setObjectName("dock_right") @@ -16214,11 +15520,7 @@ def setupUi(self, DockWidget): 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, - ) + icon20.addPixmap(QtGui.QPixmap("icons-new/Sketcher_Rectangle.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.pushPCB.setIcon(icon20) self.pushPCB.setObjectName("pushPCB") self.gridLayout_8.addWidget(self.pushPCB, 3, 3, 1, 1) @@ -16238,11 +15540,7 @@ def setupUi(self, DockWidget): 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, - ) + icon22.addPixmap(QtGui.QPixmap("icons-new/importBoard.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.LoadBoard.setIcon(icon22) self.LoadBoard.setObjectName("LoadBoard") self.gridLayout_8.addWidget(self.LoadBoard, 2, 0, 1, 1) @@ -16252,11 +15550,7 @@ def setupUi(self, DockWidget): 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, - ) + icon23.addPixmap(QtGui.QPixmap("icons-new/export3DModel.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.ScaleVRML.setIcon(icon23) self.ScaleVRML.setObjectName("ScaleVRML") self.gridLayout_8.addWidget(self.ScaleVRML, 1, 0, 1, 1) @@ -16274,11 +15568,7 @@ def setupUi(self, DockWidget): self.cb_materials.setMaximumSize(QtCore.QSize(64, 128)) self.cb_materials.setText("") icon25 = QtGui.QIcon() - icon25.addPixmap( - QtGui.QPixmap("icons-new/materials.png"), - QtGui.QIcon.Normal, - QtGui.QIcon.Off, - ) + icon25.addPixmap(QtGui.QPixmap("icons-new/materials.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.cb_materials.setIcon(icon25) self.cb_materials.setObjectName("cb_materials") self.gridLayout_8.addWidget(self.cb_materials, 1, 1, 1, 1) @@ -16297,11 +15587,7 @@ def setupUi(self, DockWidget): self.cb_expStep.setMaximumSize(QtCore.QSize(128, 64)) self.cb_expStep.setText("") icon27 = QtGui.QIcon() - icon27.addPixmap( - QtGui.QPixmap("icons-new/exportPart.png"), - QtGui.QIcon.Normal, - QtGui.QIcon.Off, - ) + icon27.addPixmap(QtGui.QPixmap("icons-new/exportPart.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.cb_expStep.setIcon(icon27) self.cb_expStep.setObjectName("cb_expStep") self.gridLayout_8.addWidget(self.cb_expStep, 2, 3, 1, 1) @@ -16321,11 +15607,7 @@ def setupUi(self, DockWidget): 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, - ) + icon29.addPixmap(QtGui.QPixmap("icons-new/add_block.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.import3D.setIcon(icon29) self.import3D.setObjectName("import3D") self.gridLayout_8.addWidget(self.import3D, 0, 1, 1, 1) @@ -16335,11 +15617,7 @@ def setupUi(self, DockWidget): 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, - ) + icon30.addPixmap(QtGui.QPixmap("icons-new/collisions.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.checkCollisions.setIcon(icon30) self.checkCollisions.setObjectName("checkCollisions") self.gridLayout_8.addWidget(self.checkCollisions, 3, 1, 1, 1) @@ -16349,11 +15627,7 @@ def setupUi(self, DockWidget): 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, - ) + icon31.addPixmap(QtGui.QPixmap("icons-new/export3DStep.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.export3DStep.setIcon(icon31) self.export3DStep.setObjectName("export3DStep") self.gridLayout_8.addWidget(self.export3DStep, 3, 0, 1, 1) @@ -16571,7 +15845,7 @@ def setupUi(self, DockWidget): self.makeUnion.clicked.connect(group_part_union) self.makeCompound.clicked.connect(group_part) self.config_ini_Lbl.linkActivated.connect(self.link) - ("" + ini_file_full_path_bold + "") + "" + 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")) @@ -17109,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' @@ -17169,7 +16443,6 @@ def onHelp(self): # paramGet = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/MainWindow") # if 'dark' in paramGet.GetString("StyleSheet").lower(): #we are using a StyleSheet font_color = """""" - font_color = """""" # FreeCADGui.getMainWindow().palette().background().color() sayw("kicad StepUp version " + str(___ver___)) @@ -17316,14 +16589,8 @@ def Export3DStepF(): 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" - else: - ext_ = ".step" if not (prefs_.GetBool("not_native_dlg")): - name, Filter = PySide.QtGui.QFileDialog.getSaveFileName( + name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName( None, "Export 3D STEP/stpZ ...", make_unicode(os.path.join(last_3d_path, def_fn) + ext_), @@ -17411,7 +16678,7 @@ def Export3DStepF(): sayerr( "to export STEP it is necessary to use StepUp Workbench
    instead of the single Macro
    (because of " + str(fcv) - + " FC bug)" + + " FC bug)", ) msg = ( """to export STEP it is necessary to use StepUp Workbench
    instead of the single Macro
    (because of """ @@ -17423,10 +16690,7 @@ def Export3DStepF(): say("including sketch in grp") FreeCAD.ActiveDocument.getObject(sk[1]).addObject(FreeCAD.ActiveDocument.getObject(sk[0])) stop - if fcb: - cpmode = "compound" - else: - cpmode = "part" + cpmode = "compound" if fcb else "part" suffix = "_" to_export_name = kicadStepUpCMD.deep_copy(doc, cpmode, suffix) # to_export_name=FreeCAD.ActiveDocument.ActiveObject.Name @@ -17541,10 +16805,9 @@ def Import3DModelF(): if len(last_3d_path) == 0: 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( + name, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( None, "Import 3D File...", make_unicode(last_3d_path), @@ -17707,7 +16970,7 @@ def setupUi(self, LayerSelection): 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") @@ -17717,7 +16980,7 @@ def setupUi(self, LayerSelection): 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") @@ -17827,10 +17090,7 @@ def PushPCB(): global last_3d_path, start_time, load_sketch, last_pcb_path, edge_width # say("export3DSTEP") if not load_sketch: - msg = translate( - "PushPCB", - "Edge editing NOT supported on FC0.15!
    please upgrade your FC release", - ) + 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) @@ -17917,10 +17177,9 @@ def PushPCB(): # 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( + name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName( None, "Push Sketch PCB Edge to KiCad board ...", make_unicode(last_pcb_path), @@ -17956,10 +17215,7 @@ def PushPCB(): 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, - ) + 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!""" @@ -18011,10 +17267,9 @@ def Sync3DModel(): # 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( + fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( None, "Load KiCad PCB board data...", make_unicode(last_pcb_path), @@ -18040,10 +17295,7 @@ def Sync3DModel(): # fpath=filePath+os.sep+doc.Label+'.kicad_pcb' # sayerr('to '+fpath) # print fname - if fname is None: - fpath = original_filename - else: - fpath = fname + fpath = original_filename if fname is None else fname sayerr("Loading from " + fpath) # stop if len(fpath) > 0: @@ -18129,7 +17381,7 @@ def Sync3DModel(): else: 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) @@ -18269,10 +17521,9 @@ def PushMoved(): # 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( + fname, _Filter = PySide.QtGui.QFileDialog.getSaveFileName( None, "Push 3D PCB position(s) to KiCad board ...", make_unicode(last_pcb_path), @@ -18298,10 +17549,7 @@ def PushMoved(): # fpath=filePath+os.sep+doc.Label+'.kicad_pcb' # sayerr('to '+fpath) # print fname - if fname is None: - fpath = original_filename - else: - fpath = fname + fpath = original_filename if fname is None else fname sayerr("saving to " + fpath) # stop if len(fpath) > 0: @@ -18506,15 +17754,12 @@ def getModelsData(mypcb): if float(lynbr) == Top_lvl: LvlTopName = mypcb.layers[f"{str(lynbr)}"][0] if float(lynbr) == Edge_Cuts_lvl: - mypcb.layers[f"{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_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"): @@ -18593,11 +17838,7 @@ def getModelsData(mypcb): # 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, - ] + 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, @@ -18686,10 +17927,9 @@ def PullMoved(): # 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( + fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( None, "Pull 3D model position(s) from pcbnew File...", make_unicode(last_pcb_path), @@ -18715,10 +17955,7 @@ def PullMoved(): # fpath=filePath+os.sep+doc.Label+'.kicad_pcb' # sayerr('to '+fpath) # print fname - if fname is None: - fpath = original_filename - else: - fpath = fname + fpath = original_filename if fname is None else fname sayerr("loading from " + fpath) # stop if len(fpath) > 0: @@ -18775,10 +18012,7 @@ def PullMoved(): 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] + 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) @@ -18944,19 +18178,11 @@ def PushFootprint(): # 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], - ) + 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, - ) + 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)) @@ -18987,31 +18213,29 @@ def PushFootprint(): 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) + 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: - 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) + 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 @@ -19045,19 +18269,11 @@ def PushFootprint(): # 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], - ) + 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, - ) + 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: @@ -19103,8 +18319,7 @@ def PushFootprint(): # 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]) @@ -19186,7 +18401,6 @@ def PushFootprint(): try: ### Begin command Part_CompJoinFeatures say("importing BOPTools") - # from PartGui import BOPTools import BOPTools import BOPTools.JoinFeatures @@ -19248,10 +18462,9 @@ def PushFootprint(): FreeCADGui.Selection.removeSelection(s) # 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( + name, _Filter = PySide.QtGui.QFileDialog.getSaveFileName( None, "Push Footprint to KiCad module ...", make_unicode(last_fp_path), @@ -19363,9 +18576,8 @@ def simplify_sketch_old(): for obj in doc.Objects: if ( obj.TypeId in {"Part::Feature", "Sketcher::SketchObject", "Part::Part2DObjectPython"} - ): - if obj.Name not in obj_list_prev: - obj_list_after.append(obj.Name) + ) 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: @@ -19420,14 +18632,24 @@ def simplify_sketch(): if hasattr(sel[0], "GeometryFacadeList"): Gm = sel[0].GeometryFacadeList for g in Gm: - 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): + 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 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) or "Ellipse" in str(g) or "Parabola" in str(g) or "Hyperbola" 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 not isConstruction(g): # g.Construction: # adding only non construction geo new_edge_list.append(g) @@ -19451,8 +18673,7 @@ def simplify_sketch(): 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") if len(new_edge_list) > 0: @@ -19565,8 +18786,7 @@ def normalize_bsplines(): # 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 @@ -19662,10 +18882,7 @@ def export_footprint(fname=None, flabel=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 + fp_name = FreeCAD.ActiveDocument.Name if flabel == "" or flabel is None else flabel # print(fp_name, 'fp_name1') for s in sel: @@ -19709,9 +18926,8 @@ def export_footprint(fname=None, flabel=None): for obj in doc.Objects: if ( obj.TypeId in {"Part::Feature", "Sketcher::SketchObject", "Part::Part2DObjectPython"} - ): - if obj.Name not in obj_list_prev: - obj_list_after.append(obj.Name) + ) 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: @@ -19894,60 +19110,42 @@ def export_footprint(fname=None, flabel=None): 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 + 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 + 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 + 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 + 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 + 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 + edge_thick = float(tk) if tk != "" else tk_d lyr = "Edge.Cuts" else: lyr = "skip" @@ -20003,10 +19201,7 @@ def export_footprint(fname=None, flabel=None): # 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 + edge_thick = float(tk) if tk != "" else tk_d # print (lyr) sk = FreeCAD.ActiveDocument.getObjectsByLabel(lyr)[0] if hasattr(sk, "GeometryFacadeList"): @@ -20022,7 +19217,7 @@ def export_footprint(fname=None, flabel=None): sk_ge.Edges[0].Curve.Center.x, sk_ge.Edges[0].Curve.Center.y, sk.Label, - ] + ], ) else: Gm = sk.Geometry @@ -20037,7 +19232,7 @@ def export_footprint(fname=None, flabel=None): sk_ge.Edges[0].Curve.Center.x, sk_ge.Edges[0].Curve.Center.y, sk.Label, - ] + ], ) # lyr=u'Pads_Geom' pgeom.append(border) @@ -21268,10 +20463,7 @@ def createFpPad(pad, offset, tp, _drills=None): if tp == "PadsAll": tp = "TH" ptp = "thru_hole" - if tp == "TH": - ptp = "thru_hole" - else: - ptp = "np_thru_hole" + ptp = "thru_hole" if tp == "TH" else "np_thru_hole" # sayw (pad) found_drill = False if pad[0] == "circle": @@ -21312,12 +20504,7 @@ def createFpPad(pad, offset, tp, _drills=None): 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}" - + "))" + drill_str + " (offset " + f"{cx - d[0]:.3f}" + " " + f"{cy - d[1]:.3f}" + "))" ) # +")" cx = d[0] cy = d[1] @@ -21360,10 +20547,7 @@ def createFpPad(pad, offset, tp, _drills=None): ptp = "smd" pad_layers = " (layers F.Cu F.Paste F.Mask))" drill_str = "" # "(drill 0)" - if sx == sy: - pshp = "circle" - else: - pshp = "oval" + 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 " @@ -21428,8 +20612,8 @@ def createFpPad(pad, offset, tp, _drills=None): else: sy = abs(pad[0][2] - pad[0][4]) py = (pad[0][2] + pad[0][4]) / -2 - # print pad[0];print pad[1] - # stop + # print pad[0];print pad[1] + # stop found_drill = False if len(_drills) > 0: for d in _drills: @@ -21446,7 +20630,7 @@ def createFpPad(pad, offset, tp, _drills=None): + ":" + str(sx) + "," - + str(sy) + + str(sy), ) found_drill = True break @@ -21459,12 +20643,7 @@ def createFpPad(pad, offset, tp, _drills=None): 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}" - + "))" + drill_str + " (offset " + f"{px - d[0]:.3f}" + " " + f"{py - d[1]:.3f}" + "))" ) # +")" px = d[0] py = d[1] @@ -21480,9 +20659,7 @@ def createFpPad(pad, offset, tp, _drills=None): drill_str = "(drill " + f"{sx:.3f}" + ")" ptype = "circle" else: - drill_str = ( - "(drill oval " + f"{sx:.3f}" + " " + f"{sy:.3f}" + ")" - ) # "(drill 0)" + drill_str = "(drill oval " + f"{sx:.3f}" + " " + f"{sy:.3f}" + ")" # "(drill 0)" ptype = "oval" else: # print('pad[-1] Rect',pad[-1]) @@ -21509,9 +20686,7 @@ def createFpPad(pad, offset, tp, _drills=None): drill_str = "(drill " + f"{sx:.3f}" + ")" ptype = "circle" else: - drill_str = ( - "(drill oval " + f"{sx:.3f}" + " " + f"{sy:.3f}" + ")" - ) # "(drill 0)" + drill_str = "(drill oval " + f"{sx:.3f}" + " " + f"{sy:.3f}" + ")" # "(drill 0)" ptype = "oval" else: # print('pad[-1] Rect 2',pad[-1]) @@ -21617,7 +20792,7 @@ def createFpPad(pad, offset, tp, _drills=None): + ":" + str(sx) + "," - + str(sy) + + 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!') @@ -21632,12 +20807,7 @@ def createFpPad(pad, offset, tp, _drills=None): 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}" - + "))" + drill_str + " (offset " + f"{px - d[0]:.3f}" + " " + f"{py - d[1]:.3f}" + "))" ) # +")" px = d[0] py = d[1] @@ -21649,9 +20819,7 @@ def createFpPad(pad, offset, tp, _drills=None): 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 " + 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" @@ -21682,9 +20850,7 @@ def createFpPad(pad, offset, tp, _drills=None): 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 " + 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" @@ -21825,7 +20991,7 @@ def createFpPad(pad, offset, tp, _drills=None): + ":" + str(sx) + "," - + str(sy) + + 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!') @@ -21835,19 +21001,12 @@ def createFpPad(pad, offset, tp, _drills=None): ### OFFSET if found_drill: if d[2] != d[3]: - drill_str = ( - "(drill oval " + f"{abs(d[2]):.3f}" + " " + f"{abs(d[3]):.3f}" - ) # +")" + drill_str = "(drill oval " + f"{abs(d[2]):.3f}" + " " + f"{abs(d[3]):.3f}" # +")" else: 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}" - + "))" + drill_str + " (offset " + f"{px - d[0]:.3f}" + " " + f"{-py - d[1]:.3f}" + "))" ) # +")" px = d[0] py = d[1] @@ -22813,7 +21972,7 @@ def getBoardOutline(): sk_ge.Edges[0].Vertexes[1].Point.x, sk_ge.Edges[0].Vertexes[1].Point.y, j.Label, - ] + ], ) # outline.append([ # 'line', @@ -22832,7 +21991,7 @@ def getBoardOutline(): sk_ge.Edges[0].Curve.Center.x, sk_ge.Edges[0].Curve.Center.y, j.Label, - ] + ], ) # outline.append([ # 'circle', @@ -22864,7 +22023,7 @@ def getBoardOutline(): sk_ge.Edges[0].Vertexes[1].Point, sk_ge.Edges[0].Orientation, j.Label, - ] + ], ) ##j.Geometry[k].Center.x, ##j.Geometry[k].Center.y, @@ -22907,14 +22066,16 @@ def getBoardOutline(): elif bs.Degree > maxDegree: # degree too high. We need to approximate the curve bs = bs.approximateBSpline( - edge_tolerance, maxSegments, maxDegree + edge_tolerance, + maxSegments, + maxDegree, ) # (tolerance, maxSegments, maxDegree) # Generate to a list of bezier curves bezier_list.extend( - bs.toBezier() + 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) @@ -22932,7 +22093,7 @@ def getBoardOutline(): 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__\ @@ -22970,7 +22131,7 @@ def getBoardOutline(): 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__\ @@ -23021,7 +22182,7 @@ def getBoardOutline(): g.EndPoint, "Forward", j.Label, - ] + ], ) # elif (accept_spline) and ('Parabola' in type(j.Geometry[k]).__name__ or 'Hyperbola' in type(j.Geometry[k]).__name__): @@ -23074,11 +22235,8 @@ def getBoardOutline(): 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") + "; " - ) + 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: @@ -23094,7 +22252,7 @@ def getBoardOutline(): + str(exc_tb.tb_lineno) + "\nerror value: " + str(e.args[0]) - + "\n" + + "\n", ) # print (to_discretize) # stop @@ -23119,15 +22277,10 @@ def createEdge(edg, ofs, sklayer=None, pcb_ver=None): # if y < self.minY: # self.minY = y - if sklayer is None: - layer = "Edge.Cuts" - else: - layer = sklayer + layer = "Edge.Cuts" if sklayer is None else sklayer if edg[0] == "line": if pcb_ver is None or pcb_ver < 20211014: - 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 = 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: @@ -23222,9 +22375,9 @@ def createEdge(edg, ofs, sklayer=None, pcb_ver=None): # 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 + # .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 = 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}))" @@ -23510,10 +22663,7 @@ def remove_basic_geom(c_name, to_disc): # 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 + Gm = s.GeometryFacadeList if hasattr(s, "GeometryFacadeList") else s.Geometry # if hasattr(Gm[i],'Construction'): # if not Gm[i].Construction: if isConstruction(Gm[i]): @@ -23549,10 +22699,7 @@ def split_basic_geom(c_name, to_disc): # 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 + Gm = s.GeometryFacadeList if hasattr(s, "GeometryFacadeList") else s.Geometry # if hasattr(Gm[i],'Construction'): # if not Gm[i].Construction: if isConstruction(Gm[i]): @@ -23576,10 +22723,7 @@ def check_geom(sk_name, ofs=None): outline = [] for k in range(len(j.Geometry)): # print(type(j.Geometry[k]).__name__) - if hasattr(j, "GeometryFacadeList"): - Gm = j.GeometryFacadeList - else: - Gm = j.Geometry + Gm = j.GeometryFacadeList if hasattr(j, "GeometryFacadeList") else j.Geometry # if hasattr(Gm[k],'Construction'): if isConstruction(Gm[k]): sayw("construnction skipped") @@ -23600,7 +22744,7 @@ def check_geom(sk_name, ofs=None): 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', @@ -23619,7 +22763,7 @@ def check_geom(sk_name, ofs=None): sk_ge.Edges[0].Curve.Center.x + ofs[0], sk_ge.Edges[0].Curve.Center.y + ofs[1], j.Label, - ] + ], ) # outline.append([ # 'circle', @@ -23661,7 +22805,7 @@ def check_geom(sk_name, ofs=None): sk_ge.Edges[0].Vertexes[1].Point, sk_ge.Edges[0].Orientation, j.Label, - ] + ], ) ## maxRadius=3500 ## sayerr(j.Geometry[k].Radius) @@ -23868,10 +23012,7 @@ def export_pcb(fname=None, sklayer=None, skname=None): # sayerr('to '+fpath) # print fname - if fname is None: - fpath = original_filename - else: - fpath = fname + fpath = original_filename if fname is None else fname sayerr("saving to " + fpath) # stop @@ -24023,12 +23164,11 @@ def export_pcb(fname=None, sklayer=None, skname=None): 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 + 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 @@ -24188,10 +23328,10 @@ def export_pcb(fname=None, sklayer=None, skname=None): # print(newcontent) else: 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" + "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

    """ + """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: @@ -24262,9 +23402,7 @@ def export_pcb(fname=None, sklayer=None, skname=None): # stop obj_list_after = [] for obj in doc.Objects: - if ( - obj.TypeId in {"Part::Feature", "Sketcher::SketchObject", "Part::Part2DObjectPython"} - ): + 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 @@ -24648,22 +23786,8 @@ def push3D2pcb(s, cnt, tsp): # 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 + 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 @@ -24671,31 +23795,16 @@ def push3D2pcb(s, cnt, tsp): # print (old_pos) # new_pos=old_pos.split('(at')[0]+'(at 1.23 5.67 890' elif ( - len( - re.findall( - r"\s*\(uuid(\s.*" + tsp.lower() + r'"*\))', - data, - re.MULTILINE | re.DOTALL, - ) - ) - > 0 - or len( - re.findall( - r"\s*\(uuid(\s.*" + tsp.upper() + r'"*\))', - data, - re.MULTILINE | re.DOTALL, - ) - ) - > 0 + 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 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 + 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 @@ -24730,10 +23839,9 @@ def push3D2pcb(s, cnt, tsp): 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) + 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) @@ -24747,10 +23855,7 @@ def push3D2pcb(s, cnt, tsp): bbpa = -bbpa # new_angle=bbpa+z_rot else: - bbpa = round( - FreeCAD.ActiveDocument.getObject(s.Name).Placement.Rotation.toEuler()[0], - 1, - ) + 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]: @@ -24762,10 +23867,7 @@ def push3D2pcb(s, cnt, tsp): 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(f"{float(mod_old_angle):.3f}") - else: - mod_old_angle = 0 + 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))+\ @@ -24794,10 +23896,7 @@ def push3D2pcb(s, cnt, tsp): 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 + 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("))") @@ -25236,20 +24335,17 @@ def singleInstance(): 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 = 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 + | QtGui.QDockWidget.DockWidgetClosable, ) # KSUWidget.setFeatures( QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable|QtGui.QDockWidget.DockWidgetClosable ) KSUWidget.setFeatures( - QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable + QtGui.QDockWidget.DockWidgetMovable | QtGui.QDockWidget.DockWidgetFloatable, ) # |QtGui.QDockWidget.DockWidgetClosable ) ksu_in_tab = False diff --git a/kicad_parser.py b/kicad_parser.py index 781b300..9e99598 100644 --- a/kicad_parser.py +++ b/kicad_parser.py @@ -53,11 +53,8 @@ # 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(_): @@ -140,10 +137,7 @@ def isZero(f): def makeColor(*color): if len(color) == 1: - if isinstance(color[0], string_types): - color = int(color[0], 0) - else: - color = color[0] + 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) @@ -171,7 +165,7 @@ def product(v1, v2): 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))] + [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))], ) @@ -235,7 +229,7 @@ def make_oval(size, params=None): 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]), - ] + ], ) @@ -377,7 +371,7 @@ def make_gr_circle(params, width=0): [ Part.Wire(Part.makeCircle(r + width * 0.5, center)), Part.Wire(Part.makeCircle(r - width * 0.5, center, Vector(0, 0, -1))), - ] + ], ) @@ -388,10 +382,7 @@ def make_gr_circle_outl(params, width=0): 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), - ] + return [Part.makeCircle(r + width * 0.5, center), Part.makeCircle(r - width * 0.5, center)] # def make_gr_circle_outl(params, width=0): @@ -502,8 +493,7 @@ def getFaceCompound(shape, wire=False): 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") return Part.makeCompound(objs) @@ -593,8 +583,8 @@ def loadModel(filename): obj = (obj.Shape.copy(), obj.ViewObject.DiffuseColor, mtime) _model_cache[filename] = obj return obj - except Exception as ex: - logger.exception(f"failed to load model: {ex}") + except Exception: + logger.exception("failed to load model") finally: for o in dobjs: doc.removeObject(o.Name) @@ -721,7 +711,7 @@ 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) @@ -863,11 +853,7 @@ def _initStackUp(self): if self.stackup: 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 @@ -958,13 +944,7 @@ def filterLayer(self, p): 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", - ) + self._log("skip layer {}, {}, {}", self.layer, self.layer_match, layers, level="trace") return True return None @@ -976,9 +956,8 @@ def netName(self, p): def _log(self, msg, *arg, **kargs): level = "info" - if kargs: - if "level" in kargs: - level = kargs["level"] + if kargs and "level" in kargs: + level = kargs["level"] if logger.isEnabledFor(level): getattr(logger, level)(f"{self.prefix}{msg.format(*arg)}") @@ -1060,10 +1039,7 @@ def addRadiusConstraint(edge): pass for obj in objs if isinstance(objs, (list, tuple)) else (objs,): - if isinstance(obj, Part.Shape): - shape = obj - else: - shape = obj.Shape + shape = obj if isinstance(obj, Part.Shape) else obj.Shape norm = DraftGeomUtils.getNormal(shape) if not self.sketch_constraint: for wire in shape.Wires: @@ -1123,16 +1099,7 @@ 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)): @@ -1148,18 +1115,7 @@ def _makeCompound( 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: @@ -1236,9 +1192,7 @@ def _makeArea( recomputeObj(ret) # retf=Part.Face(ret.Shape.Wires) # retf=ret.Shape.Wires - to_del = [] - for o in objn: - to_del.append(o) + to_del = list(objn) # to_del.append(ret) for o in to_del: # print(o) @@ -1265,15 +1219,7 @@ def _makeWires(self, obj, name, offset=0, fill=False, label=None, fit_arcs=False objs.append(o) if comp: comp = Part.makeCompound(comp) - objs.append( - self._makeObject( - "Part::Feature", - f"{name}_wire", - label, - "Shape", - comp, - ) - ) + objs.append(self._makeObject("Part::Feature", f"{name}_wire", label, "Shape", comp)) obj = objs if fill or offset: @@ -1466,15 +1412,8 @@ def _makeShape(self, sexp, ctx, wires, non_closed=None, layer=None, at=None): 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") @@ -1520,10 +1459,9 @@ def makeBoard( self._popLog() - if not wires and not non_closed: - if not wires and not non_closed: - self._popLog("no board edges found") - return None + 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) @@ -1793,10 +1731,7 @@ def _solid(obj, name): 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) @@ -2011,21 +1946,9 @@ def _face(obj, name, label=None): if wp != "": # maui wp.translate(at) if not self.merge_pads: - pads.append( - func( - w, - "pad", - f"{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)}", - ) - ) + pads.append(func(wp, "pad", f"{i}#{j}#{p[0]}#{ref}#{self.netName(p)}")) else: pads.append(w) @@ -2283,13 +2206,7 @@ def _face(edges, label): # 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, - ) - ) + 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) @@ -2312,7 +2229,7 @@ def _face(edges, label): makeVect([e.Vertexes[0].X, -e.Vertexes[0].Y]), makeVect([e.Vertexes[1].X, -e.Vertexes[1].Y]), width / 2.0, - ) + ), ) except: pass @@ -2321,10 +2238,7 @@ def _face(edges, label): # 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 + width = a.stroke.width if hasattr(a, "stroke") else a.width aco = _wire(ac.Edges, self.layer) wst.append(aco.Shape) tbd.append(aco) @@ -2372,10 +2286,7 @@ def _face(edges, label): 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 + width = pl.stroke.width if hasattr(pl, "stroke") else pl.width for e in pln.Edges: # aco=_wire(e,self.layer) wst.append( @@ -2383,7 +2294,7 @@ def _face(edges, label): 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) @@ -2422,11 +2333,7 @@ def _face(edges, label): self._popLog("sketch done") fitView() - return ( - obj, - tl, - tbd, - ) # ,add_rot # obj, thicklines, to be deleted, additional rotation in deg + return obj, tl, tbd # ,add_rot # obj, thicklines, to be deleted, additional rotation in deg def setSketchColor(self, obj, otype): if not self.add_feature: @@ -2488,10 +2395,7 @@ def _face(edges, label): 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 @@ -2506,14 +2410,7 @@ def _face(edges, label): 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, - ) + self._log("making {} tracks {} of width {:.2f}, ({}/{})", len(ss), name, width, i, count) i += len(ss) edges = [] for tp, s in ss: @@ -2521,17 +2418,13 @@ def _face(edges, label): if s.start != s.end: edges.append(Part.makeLine(makeVect(s.start), makeVect(s.end))) else: - self._log( - "Line (Track) through identical points {}", - s.start, - level="warning", - ) + 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") elif s.start != s.end: edges.append( - Part.ArcOfCircle(makeVect(s.end), makeVect(s.mid), makeVect(s.start)).toShape() + Part.ArcOfCircle(makeVect(s.end), makeVect(s.mid), makeVect(s.start)).toShape(), ) else: start = makeVect(s.start) @@ -2540,10 +2433,7 @@ def _face(edges, label): edges.append(Part.makeCircle(r, (middle - start) / 2)) else: self._log("Unknown track type: {}", tp, level="warning") - if self.merge_tracks: - label = f"{width}" - else: - label = f"{width}#{name}" + label = f"{width}" if self.merge_tracks else f"{width}#{name}" objs.append(func(edges, label=label)) if objs: @@ -2575,10 +2465,7 @@ def _wire(obj, fill=False): 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"), - ) + 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) @@ -2665,14 +2552,7 @@ def build(start, end): def makePolys(self, shape_type="face", thickness=0.05, fit_arcs=True, holes=False, prefix=""): """For making outlier gr_poly as if it was zone, e.g. export from Gerber viewer""" poly_holes = [] - objs = self._makePolygons( - getattr(self.pcb, "gr_poly", None), - "poly", - poly_holes, - shape_type, - thickness, - prefix, - ) + objs = self._makePolygons(getattr(self.pcb, "gr_poly", None), "poly", poly_holes, shape_type, thickness, prefix) if not objs: return None @@ -2719,16 +2599,7 @@ def makeZones(self, shape_type="face", thickness=0.05, fit_arcs=True, holes=Fals def isBottomLayer(self): return self.layer_type == 31 - def makeCopper( - self, - shape_type="face", - thickness=0.05, - fit_arcs=True, - holes=False, - z=0, - prefix="", - fuse=False, - ): + def makeCopper(self, shape_type="face", thickness=0.05, fit_arcs=True, holes=False, z=0, prefix="", fuse=False): self._pushLog("making copper layer {}...", self.layer, prefix=prefix) @@ -2745,12 +2616,7 @@ def makeCopper( solid = False sub_fit_arcs = False - for name, offset in ( - ("Pads", thickness), - ("Tracks", 0.5 * thickness), - ("Zones", 0), - ("Polys", thickness), - ): + for name, offset in (("Pads", thickness), ("Tracks", 0.5 * thickness), ("Zones", 0), ("Polys", thickness)): obj = getattr(self, f"make{name}")( fit_arcs=sub_fit_arcs, holes=holes, @@ -2827,10 +2693,7 @@ def makeCoppers( if not len(layers) == len(thicknesses): raise RuntimeError("No copper thickness found for layer ") - if len(layers) == 1: - z_step = 0 - else: - z_step = (board_thickness + thicknesses[-1]) / (len(layers) - 1) + z_step = 0 if len(layers) == 1 else (board_thickness + thicknesses[-1]) / (len(layers) - 1) offsets = [board_thickness - i * z_step for i, _ in enumerate(layers)] thickness = max(thicknesses) @@ -2918,15 +2781,9 @@ def loadParts(self, z=0, combo=False, prefix=""): at_bottom = self.isBottomLayer() if z == 0: - if at_bottom: - z = -0.1 - else: - z = self.pcb.general.thickness + 0.1 + z = -0.1 if at_bottom else self.pcb.general.thickness + 0.1 - if self.add_feature or combo: - parts = [] - else: - parts = {} + parts = [] if self.add_feature or combo else {} for module_idx, m in enumerate(self.pcb.module): if unquote(m.layer) != self.layer: @@ -2944,14 +2801,7 @@ def loadParts(self, z=0, combo=False, prefix=""): objs = [] for model_idx, model in enumerate(m.model): path = os.path.splitext(model[0])[0] - self._log( - "loading model {}/{} {} {} {}...", - model_idx, - len(m.model), - ref, - value, - model[0], - ) + self._log("loading model {}/{} {} {} {}...", model_idx, len(m.model), ref, value, model[0]) for e in (".stp", ".STP", ".step", ".STEP"): filename = os.path.join(self.part_path, path + e) mobj = loadModel(filename) @@ -3069,10 +2919,7 @@ def make( 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: with contextlib.suppress(Exception): objs.ViewObject.SelectionStyle = 1 diff --git a/selection2edges.py b/selection2edges.py index 4dc798f..5598a09 100644 --- a/selection2edges.py +++ b/selection2edges.py @@ -48,11 +48,7 @@ def placement_tol(vect1, vect2, tol): return 0 return 1 - if placement_tol( - FreeCADGui.ActiveDocument.activeView().getViewDirection(), - FreeCAD.Vector(1.0, 0.0, 0.0), - tol, - ): + 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)) diff --git a/step_amend.py b/step_amend.py index ffd5dce..a1d05af 100644 --- a/step_amend.py +++ b/step_amend.py @@ -13,6 +13,7 @@ # import FreeCAD # import FreeCADGui + # support both gz and zipfile archives # Catia seems to use gz, Inventor zipfile # improved import, open and export @@ -75,11 +76,7 @@ def transp_rmv(filename): 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, - ) + line = re.sub(rb"SURFACE_STYLE_TRANSPARENT\(1.\)", b"SURFACE_STYLE_TRANSPARENT(0.)", line) found_transp_issue = True # print(line) fogz.write(line) @@ -99,11 +96,7 @@ def transp_rmv(filename): 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, - ) + line = re.sub(rb"SURFACE_STYLE_TRANSPARENT\(1.\)", b"SURFACE_STYLE_TRANSPARENT(0.)", line) found_transp_issue = True # print(line) fo.write(line) diff --git a/test-mb.py b/test-mb.py index 27d8953..7a81733 100644 --- a/test-mb.py +++ b/test-mb.py @@ -1,5 +1,3 @@ -from PySide import 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?") @@ -17,14 +15,10 @@ # msg_box.setDefaultButton(QtGui.QMessageBox.Cancel) # # ret = msg_box.exec_() + +from PySide import QtCore from PySide.QtCore import SIGNAL -from PySide.QtGui import ( - QDialog, - QFormLayout, - QLabel, - QLineEdit, - QPushButton, -) +from PySide.QtGui import QDialog, QFormLayout, QLabel, QLineEdit, QPushButton if 0: @@ -36,7 +30,7 @@ def __init__(self, parent=None): # 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'" + "This will remove ALL Suffix from selection objects. .\nDo you want to continue?\n\n'suffix'", ) self.le = QLineEdit() self.le.setObjectName("suffix_filter") @@ -101,7 +95,7 @@ def __init__(self, parent=None): self.txt = QLabel() self.txt.setText( - "This will remove ALL Suffix from selection objects. \nDo you want to continue?\n\n'suffix'" + "This will remove ALL Suffix from selection objects. \nDo you want to continue?\n\n'suffix'", ) self.le = QLineEdit() self.le.setObjectName("suffix_filter") diff --git a/tracks.py b/tracks.py index 6c2c44c..e0c080f 100644 --- a/tracks.py +++ b/tracks.py @@ -56,7 +56,7 @@ def getFCversion(): FC_minorV = int(float(FreeCAD.Version()[1])) try: FC_git_Nbr = int( - float(FreeCAD.Version()[2].strip(" (Git)").split(" ")[0]) + float(FreeCAD.Version()[2].strip(" (Git)").split(" ")[0]), ) # +int(FreeCAD.Version()[2].strip(" (Git)").split(' ')[1]) except: FC_git_Nbr = 0 @@ -65,9 +65,8 @@ def getFCversion(): 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 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: @@ -146,6 +145,9 @@ def make_unicode_t(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): @@ -206,15 +208,11 @@ def extrude_holes(holes, w): FreeCADGui.ActiveDocument.getObject(holes.Name).Visibility = False - - def cut_fuzzy(base, tool, ftol): Part.show(base.Shape.cut(tool.Shape, ftol)) - - def cut_out_tracks(pcbsk, tracks, tname_sfx): # import tracks; import importlib;importlib.reload(tracks) @@ -283,7 +281,7 @@ def cut_out_tracks(pcbsk, tracks, tname_sfx): 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 + Common_Top.Name, ).Shape new_label = tracks.Label + "_cut" FreeCADGui.ActiveDocument.ActiveObject.ShapeColor = FreeCADGui.ActiveDocument.getObject(Common_Top.Name).ShapeColor @@ -291,10 +289,10 @@ def cut_out_tracks(pcbsk, tracks, tname_sfx): 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 + Common_Top.Name, ).DiffuseColor FreeCADGui.ActiveDocument.ActiveObject.Transparency = FreeCADGui.ActiveDocument.getObject( - Common_Top.Name + Common_Top.Name, ).Transparency FreeCAD.ActiveDocument.ActiveObject.Label = new_label tracks_ct_Name = FreeCAD.ActiveDocument.ActiveObject.Name @@ -344,14 +342,12 @@ def simple_cpy(obj, lbl): def addtracks(fname=None): global start_time, last_pcb_path, min_drill_size global use_LinkGroups, use_AppPart, tracks_version - - 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 = "" pg = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/kicadStepUp") if fname is None: last_pcb_path = pg.GetString("last_pcb_path") @@ -360,8 +356,11 @@ def addtracks(fname=None): 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" + fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( + None, + "Open File...", + make_unicode(last_pcb_path), + "*.kicad_pcb", ) else: fname, _Filter = PySide.QtGui.QFileDialog.getOpenFileName( @@ -371,7 +370,7 @@ def addtracks(fname=None): "*.kicad_pcb", options=QtWidgets.QFileDialog.DontUseNativeDialog, ) - path, _name = os.path.split(fname) + _path, _name = os.path.split(fname) # filename=os.path.splitext(name)[0] filename = fname # importDXF.open(os.path.join(dirname,filename)) @@ -404,10 +403,6 @@ def addtracks(fname=None): ] # print(pcb_color_pos) trk_col = assign_col[pcb_color_pos] - if pcb_color_pos == 9: - pass - else: - pass # mypcb = KicadPCB.load(filename) # pcbThickness = float(mypcb.general.thickness) # print (mypcb.general.thickness) @@ -427,7 +422,9 @@ def addtracks(fname=None): # 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) + 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) @@ -463,7 +460,7 @@ def addtracks(fname=None): # 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] @@ -495,69 +492,61 @@ def addtracks(fname=None): topZones = None deltaz = 0.01 # 10 micron add_toberemoved = [] - if FreeCAD.ActiveDocument is not None: - objsNum = len(FreeCAD.ActiveDocument.Objects) - else: - objsNum = 0 + 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: - 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 + 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 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: - 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 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 + k_test = lp.layer if hasattr(lp, "layer") else lp.layers if "F.Cu" not in k_test: continue # print(lp, lp.fill) @@ -565,10 +554,9 @@ def addtracks(fname=None): continue # print('solid') ply_lines = [] - 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); @@ -576,7 +564,7 @@ def addtracks(fname=None): 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: @@ -586,10 +574,9 @@ def addtracks(fname=None): 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) @@ -606,18 +593,12 @@ def addtracks(fname=None): 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 + 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) - if hasattr(pl, "stroke"): - width = pl.stroke.width - else: - width = pl.width + width = pl.stroke.width if hasattr(pl, "stroke") else pl.width for e in pln.Edges: # aco=_wire(e,self.layer) wst.append( @@ -625,7 +606,7 @@ def addtracks(fname=None): 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') @@ -650,10 +631,7 @@ def addtracks(fname=None): # 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 + k_test = r.layer if hasattr(r, "layer") else r.layers if "F.Cu" not in k_test: continue if r.fill != "solid": @@ -664,25 +642,19 @@ def addtracks(fname=None): 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), - ) + 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), - ) + 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) @@ -697,10 +669,7 @@ def addtracks(fname=None): 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 + k_test = c.layer if hasattr(c, "layer") else c.layers if "F.Cu" not in k_test: continue if c.fill != "solid": @@ -824,15 +793,24 @@ def addtracks(fname=None): elif use_LinkGroups: if topPads is not None: FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).ViewObject.dropObject( - topPads, topPads, "", [] + topPads, + topPads, + "", + [], ) if topTracks is not None: FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).ViewObject.dropObject( - topTracks, topTracks, "", [] + topTracks, + topTracks, + "", + [], ) if topZones is not None: FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).ViewObject.dropObject( - topZones, topZones, "", [] + topZones, + topZones, + "", + [], ) # try: #doing bot tracks layer # pcb.setLayer(LvlBotName) @@ -843,58 +821,53 @@ def addtracks(fname=None): botPads = None botTracks = None botZones = None - if FreeCAD.ActiveDocument is not None: - objsNum = len(FreeCAD.ActiveDocument.Objects) - else: - objsNum = 0 + 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: - if 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 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 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: - 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 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='') @@ -976,15 +949,24 @@ def addtracks(fname=None): elif use_LinkGroups: if botPads is not None: FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).ViewObject.dropObject( - botPads, botPads, "", [] + botPads, + botPads, + "", + [], ) if botTracks is not None: FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).ViewObject.dropObject( - botTracks, botTracks, "", [] + botTracks, + botTracks, + "", + [], ) if botZones is not None: FreeCAD.ActiveDocument.getObject("Board_Geoms" + ftname_sfx).ViewObject.dropObject( - botZones, botZones, "", [] + botZones, + botZones, + "", + [], ) if skip_import_zones: FreeCAD.Console.PrintWarning("import Zone(s) skipped" + "\n") diff --git a/utf8test.py b/utf8test.py index b4d6344..0909614 100644 --- a/utf8test.py +++ b/utf8test.py @@ -10,7 +10,6 @@ def check_type(input): print("string") return print("not string") - return def make_string(input):