# -*- coding: utf8 -*- #!/usr/bin/python # # This is derived from a cadquery script for generating PDIP models in X3D format # # from https://bitbucket.org/hyOzd/freecad-macros # author hyOzd ## requirements ## cadquery FreeCAD plugin ## https://github.com/jmwright/cadquery-freecad-module ## to run the script just do: freecad main_generator.py modelName ## e.g. c:\freecad\bin\freecad main_generator.py DIP8 ## the script will generate STEP and VRML parametric models ## to be used with kicad StepUp script #* These are a FreeCAD & cadquery tools * #* to export generated models in STEP & VRML format. * #* * #* cadquery script for generating DIP socket models in STEP AP214 * #* Copyright (c) 2017 * #* Maurice https://launchpad.net/~easyw * #* Terje Io https://github.com/terjeio * #* All trademarks within this guide belong to their legitimate owners. * #* * #* 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., * #* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * #* * #**************************************************************************** __title__ = "make assorted DIP part 3D models" __author__ = "maurice, hyOzd, Stefan, Terje" __Comment__ = 'make make assorted DIP part 3D models exported to STEP and VRML for Kicad StepUP script' ___ver___ = "1.0.0 30/11/2017" # # 2017-11-25: mods by Terje: made generic in order to support class based model scripts # import sys, os import exportPartToVRML as expVRML import shaderColors import re, fnmatch # maui start import FreeCAD #, Draft, FreeCADGui #import ImportGui import FreeCADGui Gui = FreeCADGui #from Gui.Command import * from cq_base_parameters import CaseType if FreeCAD.GuiUp: from PySide import QtGui # Import cad_tools import cq_cad_tools # Reload tools reload(cq_cad_tools) # Explicitly load all needed functions from cq_cad_tools import FuseObjs_wColors, GetListOfObjects, restore_Main_Tools, \ exportSTEP, close_CQ_Example, saveFCdoc, z_RotateObject, Color_Objects, \ checkRequirements import add_license # Sphinx workaround #1 try: QtGui except NameError: QtGui = None # try: # Gui.SendMsgToActiveView("Run") # from Gui.Command import * Gui.activateWorkbench("CadQueryWorkbench") import cadquery cq = cadquery # from Helpers import show # CadQuery Gui except: # catch *all* exceptions msg = "missing CadQuery 0.3.0 or later Module!\r\n\r\n" msg += "https://github.com/jmwright/cadquery-freecad-module/wiki\n" if QtGui is not None: reply = QtGui.QMessageBox.information(None,"Info ...",msg) # maui end # Sphinx workaround #2 try: cq checkRequirements(cq) except NameError: cq = None # #checking requirements try: close_CQ_Example(FreeCAD, Gui) except: # catch *all* exceptions print "CQ 030 doesn't open example file" global All All = None global kicadStepUptools def clear_console(): r"""Clears the FreeCAD Report & Python consoles """ mw = Gui.getMainWindow() mw.findChild(QtGui.QPlainTextEdit, "Python console").clear() mw.findChild(QtGui.QTextEdit, "Report view").clear() class ModelGenerator: r"""A class for creating 3D models :param scripts_root: the directory where the script :param script_dir: the directory where the script resides, used for adding script source link in the model files. None to disable :param saveToKicad: * True: write .step and .wrl files directly to KISYS3DMOD folder if it exists. * False: write to the _3Dmodels folder relative to *scripts_root* :type saveToKicad: ``boolean`` :param kicadStepUp: * True: add footprint to the created models * False: do not add * None: add footprint when creating single footprint :type kicadStepUp: ``boolean`` """ alt_license = [ "*", # this line is replaced with copyright string - do NOT set to empty "---", "This work is licensed under the Creative Commons CC-BY-SA 4.0 License with the following exception:", "To the extent that the creation of electronic designs that use 'Licensed Material'", "can be considered to be 'Adapted Material', then the copyright holder waives", "article 3 of the license with respect to these designs and any generated files", "which use data provided as part of the 'Licensed Material'.", "", "https://creativecommons.org/licenses/by-sa/4.0/legalcode", "---", "Please refer to http://kicad-pcb.org/libraries/license/ for further clarification of the exception.", "---", "", "Risk disclaimer:", "*USE 3D CAD DATA AT YOUR OWN RISK*", "*DO NOT RELY UPON ANY INFORMATION FOUND HERE WITHOUT INDEPENDENT VERIFICATION.*", ] def __init__(self, scripts_root, script_dir=None, saveToKicad=True, kicadStepUp=None): self.script_dir = script_dir if self.script_dir == "" or self.script_dir is None: self.script_dir = None self.models_dir = os.getenv('KISYS3DMOD') if saveToKicad else None if self.models_dir is None: self.models_dir = scripts_root + "_3Dmodels" self.models_src_dir = scripts_root + "_3DmodelsFCStd" self.footprints_dir = os.getenv('KISYSMOD') if self.footprints_dir is not None and not os.path.isdir(self.footprints_dir): self.footprints_dir = None self.kicadStepUptools = kicadStepUp self.license = None self.scriptsource = "https://github.com/easyw/kicad-3d-models-in-freecad/tree/master/cadquery/FCAD_script_generator/" def getOptions (self, argv): r"""get options from sys.argv ready to use as the *options* parameter for the :func:`makeModels` method :param argv: usually sys.argv :type argv: ``list of str`` :rtype: ``list of str`` """ return argv[2:] if len(argv) >= 3 else [] def setLicense(self, license): r"""set the license text to be added to the created models, default is to use the text from add_license.py :param license: license text :type license: ``list of str`` """ self.license = license def setScriptSource(self, url): r"""set the url (link) to the root project folder, default is easyw's script source project on github .. note:: This will only be added if the default license text is used and if so the script folder name will be automatically appended to the url :param url: script source url :type url: ``str`` """ self.scriptsource = "" if url is None else url def makeModel(self, models_dir, genericName, model, keepDocument=True, verbose=False): r"""Creates a model by calling an instance of a model generator class and writes out the model files .. note:: normally this method will be called by :func:`makeModels` but may be used directly :param models_dir: directory to write the created step and wrl files :type models_dir: ``str`` :param genericName: the generic name from the base parameter list, may be used to create the model name :type genericName: ``str`` :param model: an instance of the model class to use :type model: ``class instance`` inherited from :class:`cq_base_model.PartBase` :param keepDocument: * True: the FreeCAD document will shown after it is created, optionally with kicadStepUptools activated * False: the document window will be closed :type keepDocument: ``boolean`` """ global kicadStepUptools modelName = model.makeModelName(genericName) FreeCAD.Console.PrintMessage('\r\n' + modelName) if model.make_me != True: FreeCAD.Console.PrintMessage(' - not made') return CheckedmodelName = modelName.replace('.', '').replace('-', '_').replace('(', '').replace(')', '') FreeCAD.newDocument(CheckedmodelName) FreeCAD.setActiveDocument(CheckedmodelName) Gui.ActiveDocument = Gui.getDocument(CheckedmodelName) model.make() doc = FreeCAD.ActiveDocument objs = GetListOfObjects(FreeCAD, doc) material_substitutions = {} for i in range(0, len(objs)): Color_Objects(Gui, objs[i], shaderColors.named_colors[model.color_keys[i]].getDiffuseFloat()) material_substitutions[Gui.ActiveDocument.getObject(objs[i].Name).DiffuseColor[0][:-1]] = model.color_keys[i] if verbose: expVRML.say(material_substitutions) expVRML.say(model.color_keys) expVRML.say(model.offsets) doc.Label = CheckedmodelName while len(objs) > 1: FuseObjs_wColors(FreeCAD, FreeCADGui, doc.Name, objs[0].Name, objs[1].Name) del objs objs = GetListOfObjects(FreeCAD, doc) objs[0].Label = CheckedmodelName restore_Main_Tools() #rotate if required if (model.rotation != 0): z_RotateObject(doc, model.rotation) s = objs[0].Shape shape = s.copy() shape.Placement = s.Placement; shape.translate(model.offsets) objs[0].Placement = shape.Placement out_dir = models_dir + os.sep + model.destination_dir if not os.path.exists(out_dir): os.makedirs(out_dir) # Export STEP model exportSTEP(doc, modelName, out_dir) license_txt = list(add_license.LIST_int_license if self.license is None else self.license) # make a copy to avoid modifying the original license_txt.append("") license_txt.append("") if self.scriptsource != "" and self.script_dir is not None: license_txt.append("Generated by script, source at:") license_txt.append(self.scriptsource + self.script_dir.split(os.sep)[-1]) license_txt.append("") if verbose: expVRML.say("") add_license.addLicenseToStep(out_dir + os.sep, modelName + ".step", license_txt, model.licAuthor, model.licEmail, model.licOrgSys, model.licOrg, model.licPreProc) # Scale and export Vrml model scale = 1.0 / 2.54 objs = GetListOfObjects(FreeCAD, doc) if verbose: expVRML.say("######################################################################") expVRML.say(objs) expVRML.say("######################################################################") export_objects, used_color_keys = expVRML.determineColors(Gui, objs, material_substitutions) export_file_name = out_dir + os.sep + modelName + '.wrl' colored_meshes = expVRML.getColoredMesh(Gui, export_objects, scale) expVRML.writeVRMLFile(colored_meshes, export_file_name, used_color_keys, license_txt) # Save the doc in native FC format out_dir = self.models_src_dir + os.sep + model.destination_dir if not os.path.exists(out_dir): os.makedirs(out_dir) saveFCdoc(FreeCAD, Gui, doc, modelName, out_dir) # Place on footprint for verification if keepDocument and model.footprints_dir is not None and self.footprints_dir is not None: sys.argv = ["fc", "dummy", self.footprints_dir + os.sep + model.footprints_dir + os.sep + modelName, "savememory"] if verbose: expVRML.say('Footprint: ' + sys.argv[2]) if self.kicadStepUptools is None: try: import kicadStepUptools expVRML.say("ksu present!") self.kicadStepUptools = True kicadStepUptools.KSUWidget.close() #kicadStepUptools.KSUWidget.setWindowState(QtCore.Qt.WindowMinimized) #kicadStepUptools.KSUWidget.destroy() #for i in QtGui.qApp.topLevelWidgets(): # if i.objectName() == "kicadStepUp": # i.deleteLater() #kicadStepUptools.KSUWidget.close() except: self.kicadStepUptools = False expVRML.say("ksu not present") if not self.kicadStepUptools == False: kicadStepUptools.KSUWidget.close() reload(kicadStepUptools) kicadStepUptools.KSUWidget.close() #kicadStepUptools.KSUWidget.setWindowState(QtCore.Qt.WindowMinimized) #kicadStepUptools.KSUWidget.destroy() #display BBox if keepDocument: Gui.activateWorkbench("PartWorkbench") Gui.SendMsgToActiveView("ViewFit") Gui.activeDocument().activeView().viewAxometric() else: doc=FreeCAD.ActiveDocument FreeCAD.closeDocument(doc.Name) def makeModels(self, options, series, family, params, kicadStepUptools=None, verbose=False): r"""Instantiates model creator classes and calls :func:`makeModel` repeatedly to create model files This is the main entry point to use for creating models :param options: * options[0]: * empty - create default model from all *series* when *family* is None, otherwise the default model for a single *series* * 'all' - generate all models * 'allsmd' - generate all SMD style models * 'list' - list all model names * regexp - a filter to select the models to create :type options: ``str`` :param series: list of part creator classes inherited from :class:`cq_base_model.PartBase` :type series: ``list of classes`` :param family: index into the list of parameter classes (series) None if all :type family: ``integer or None`` :param params: instance of the class used to hold part parameters :type params: ``class instance`` inherited from :class:`cq_base_model.PartBase` Example:: import sys, os script_dir = os.path.dirname(os.path.realpath(__file__)) scripts_root = script_dir.split(script_dir.split(os.sep)[-1])[0] sys.path.append(script_dir) sys.path.append(scripts_root + "\_tools") import cq_model_generator from cq_base_model import * class my_part (PartBase) ... class my_part_params (PartParametersBase) ... family = 0 # set to None to generate all series series = [ my_part ] generator = cq_model_generator.ModelGenerator(scripts_root, script_dir) options = generator.getOptions(sys.argv) generator.make_models(options, series, family, my_part_params()) """ clear_console() FreeCAD.Console.PrintMessage('\r\nRunning...\r\n') if verbose: expVRML.say(self.models_dir) expVRML.say(options) models_made = 0 if len(options) > 0 and not params.base_params.has_key(options[0]): models = params.getAllModels(series) if options[0] == "list": for variant in sorted(models): models_made = models_made + 1 expVRML.say(variant + " ") # added spaces for pasting into .md file else: buildAllSMD = options[0] == "allsmd" qfilter = '*' if options[0] == "all" or options[0] == "allsmd" else options[0] qfilter = re.compile(fnmatch.translate(qfilter)) for variant in models.keys(): if qfilter.match(variant): params = models[variant].params model = models[variant].model(params) if (buildAllSMD == False or params.type == CaseType.SMD) and model.make_me: models_made = models_made + 1 self.makeModel(self.models_dir, variant, model, keepDocument=False, verbose=verbose) else: if family == All: models = params.getSampleModels(series) for variant in models.keys(): params = models[variant].params model = models[variant].model(params) if model.make_me: models_made = models_made + 1 self.makeModel(self.models_dir, variant, model, keepDocument=True, verbose=verbose) else: FreeCAD.Console.PrintMessage('\r\n' + model.makeModelName(variant) + ' - not made') else: variant_to_build = "" if len(options)== 0 else options[0] if variant_to_build == "": FreeCAD.Console.PrintMessage('No variant name is given! building default variants') for i in range(family, family + 1): variant = series[i].default_model if variant_to_build == "" else variant_to_build model = params.getModel(series[i], variant) if model != False: models_made = models_made + 1 self.makeModel(self.models_dir, variant, model, keepDocument=True, verbose=verbose) else: FreeCAD.Console.PrintMessage('\r\n' + variant + ' - not made') if models_made == 0: FreeCAD.Console.PrintMessage('\r\nDone - no models matched the provided filter!') else: FreeCAD.Console.PrintMessage('\r\nDone - models made: ' + str(models_made)) sys.argv = [] # clear, running kicadStepUptools changes values ### EOF ###