From 5b6db4ca5231ce46821652ff131422097cc4436e Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Fri, 11 Feb 2022 16:46:12 +0000 Subject: [PATCH 01/45] Support of extruded sketchs thanks to Munther Hindi --- freecad/gdml/GDMLColourMap.py | 621 +-- freecad/gdml/GDMLCommands.py | 2203 +++++----- freecad/gdml/GDMLMaterials.py | 173 +- freecad/gdml/GDMLObjects.py | 6886 ++++++++++++++++--------------- freecad/gdml/GDMLShared.py | 714 ++-- freecad/gdml/exportExtrusion.py | 845 ++++ freecad/gdml/exportGDML.py | 3771 +++++++++-------- 7 files changed, 8359 insertions(+), 6854 deletions(-) create mode 100644 freecad/gdml/exportExtrusion.py diff --git a/freecad/gdml/GDMLColourMap.py b/freecad/gdml/GDMLColourMap.py index fc5ed7fc3..ec4a1744a 100644 --- a/freecad/gdml/GDMLColourMap.py +++ b/freecad/gdml/GDMLColourMap.py @@ -1,41 +1,42 @@ -#************************************************************************** -#* * -#* Copyright (c) 2017 Keith Sloan * -#* (c) Dam Lambert 2020 * -#* * -#* 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 * -#* * -#* Acknowledgements : * -#* * -#************************************************************************** - -__title__="FreeCAD GDML Workbench - GDMLColourMap" +# ************************************************************************** +# * * +# * Copyright (c) 2017 Keith Sloan * +# * (c) Dam Lambert 2020 * +# * * +# * 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 * +# * * +# * Acknowledgements : * +# * * +# ************************************************************************** + +__title__ = "FreeCAD GDML Workbench - GDMLColourMap" __author__ = "Keith Sloan" __url__ = ["http://www.freecadweb.org"] import FreeCAD import FreeCADGui -#from PySide2 import QtGui, QtCore +# from PySide2 import QtGui, QtCore from PySide import QtGui, QtCore if FreeCADGui: try: _encoding = QtGui.QApplication.UnicodeUTF8 + def translate(context, text): "convenience function for Qt translator" return QtGui.QApplication.translate(context, text, None, _encoding) @@ -44,288 +45,330 @@ def translate(context, text): "convenience function for Qt translator" return QtGui.QApplication.translate(context, text, None) + def resetGDMLColourMap(): print('Reset Colour Map') global workBenchColourMap - try : - del workBenchColourMap + try: + del workBenchColourMap except NameError: - pass + pass workBenchColourMap = GDMLColourMap(FreeCADGui.getMainWindow()) + def showGDMLColourMap(): print('Display Colour Map') workBenchColourMap.show() -def lookupColour(col) : + +def lookupColour(col): global workBenchColourMap print('Lookup Colour') - try : + try: mat = workBenchColourMap.lookupColour(col) - + except NameError: workBenchColourMap = GDMLColourMap(FreeCADGui.getMainWindow()) mat = workBenchColourMap.lookupColour(col) - + return mat -#class GDMLColour(QtGui.QWidget): -#class GDMLColour(QtGui.QPushButton): + +# class GDMLColour(QtGui.QWidget): +# class GDMLColour(QtGui.QPushButton): class GDMLColour(QtGui.QLineEdit): - - def __init__(self,colour): - super().__init__() - palette = self.palette() - #palette.setColor(QtGui.QPalette.Button, QtGui.QColor(colour)) - palette.setColor(QtGui.QPalette.Base, QtGui.QColor(colour)) - #palette.setColor(QtGui.QPalette.Window, QtGui.QColor(colour)) - self.setAutoFillBackground(True) - #palette.setColor(QtGui.QPalette.Window, QtGui.QColor(QtGui.qRed)) - #palette.setColor(QtGui.QPalette.Window, QtGui.qRed) - self.setStyleSheet("QPushButton {border-color: black; border: 2px;}") - self.setPalette(palette) - #self.setFlat(True) - self.update() + + def __init__(self, colour): + super().__init__() + palette = self.palette() + # palette.setColor(QtGui.QPalette.Button, QtGui.QColor(colour)) + palette.setColor(QtGui.QPalette.Base, QtGui.QColor(colour)) + # palette.setColor(QtGui.QPalette.Window, QtGui.QColor(colour)) + self.setAutoFillBackground(True) + # palette.setColor(QtGui.QPalette.Window, QtGui.QColor(QtGui.qRed)) + # palette.setColor(QtGui.QPalette.Window, QtGui.qRed) + self.setStyleSheet("QPushButton {border-color: black; border: 2px;}") + self.setPalette(palette) + self.setReadOnly(True) + # self.setFlat(True) + self.update() + class GDMLColourHex(QtGui.QLineEdit): - - def __init__(self,colhex): - super().__init__() - self.insert(colhex) - -class GDMLColourMapEntry(QtGui.QWidget) : - - def __init__(self,colour,colhex,material) : - super().__init__() - print('Map Entry : '+str(colour)) - self.colour = colour - self.hbox = QtGui.QHBoxLayout() - self.hbox.addWidget(GDMLColour(colour)) - self.hbox.addWidget(GDMLColourHex(colhex)) - self.hbox.addWidget(material) - self.setLayout(self.hbox) - - def dataPicker(self): - print('DataPicker') - -class GDMLColourMapList(QtGui.QScrollArea) : - - def __init__(self,matList) : - super().__init__() - # Scroll Area which contains the widgets, set as the centralWidget - # Widget that contains the collection of Vertical Box - self.widget = QtGui.QWidget() - self.matList = matList - # The Vertical Box that contains the Horizontal Boxes of labels and buttons - self.vbox = QtGui.QVBoxLayout() - self.widget.setLayout(self.vbox) - - #Scroll Area Properties - self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) - self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - self.setWidgetResizable(True) - self.setWidget(self.widget) - - def addEntry(self, colour,colhex,mat) : - from .GDMLMaterials import GDMLMaterial - print('Add Entry') - matWidget = GDMLMaterial(self.matList,mat) - self.vbox.addWidget(GDMLColourMapEntry(colour,colhex,matWidget)) - - def getMaterial(self, index) : - #print(dir(self.vbox)) - item = self.vbox.itemAt(index).widget() - #item.dumpObjectTree() - #cb = item.findChild(QtGui.QComboBox,'GDMLMaterial') - cb = item.findChildren(QtGui.QComboBox)[0] - m = cb.currentText() - print(m) - return(m) - -class GDMLColourMap(QtGui.QDialog) : -#class GDMLColourMap(QtGui.QMainWindow) : - def __init__(self, parent) : - super(GDMLColourMap, self).__init__(parent, QtCore.Qt.Tool) - self.initUI() - - def initUI(self): - self.result = userCancelled - # create our window - # define window xLoc,yLoc,xDim,yDim - self.setGeometry( 150, 450, 650, 550) - self.setWindowTitle("Map FreeCAD Colours to GDML Materials") - self.setMouseTracking(True) - self.buttonNew = QtGui.QPushButton(translate('GDML','New')) - self.buttonNew.clicked.connect(self.onNew) - self.buttonLoad = QtGui.QPushButton(translate('GDML','Load')) - self.buttonLoad.clicked.connect(self.onLoad) - self.buttonSave = QtGui.QPushButton(translate('GDML','Save')) - self.buttonSave.clicked.connect(self.onSave) - self.buttonScan = QtGui.QPushButton(translate('GDML','Scan')) - self.buttonScan.clicked.connect(self.onScan) - headerLayout = QtGui.QHBoxLayout() - headerLayout.addWidget(self.buttonNew) - headerLayout.addWidget(self.buttonLoad) - headerLayout.addWidget(self.buttonSave) - headerLayout.addWidget(self.buttonScan) - self.coloursLayout = QtGui.QGridLayout() - mainLayout = QtGui.QVBoxLayout(self) - mainLayout.addLayout(headerLayout) - mainLayout.addLayout(self.coloursLayout) - from .GDMLMaterials import getMaterialsList - self.matList = getMaterialsList() - self.mapList = GDMLColourMapList(self.matList) - self.colorDict = {} - self.scanDocument(1) - print(self.colorDict) - #for c in self.colorList : - # self.mapList.addEntry(QtGui.QColor(c[0]*255,c[1]*255,c[2]*255)) - # create Labels - self.label1 = self.mapList - self.coloursLayout.addWidget(self.label1,0,0) - # cancel button - cancelButton = QtGui.QPushButton('Cancel', self) - cancelButton.clicked.connect(self.onCancel) - cancelButton.setAutoDefault(True) - self.coloursLayout.addWidget(cancelButton, 2, 1) - - # OK button - okButton = QtGui.QPushButton('Set Materials', self) - okButton.clicked.connect(self.onOk) - self.coloursLayout.addWidget(okButton, 2, 0) - # now make the window visible - self.setLayout(mainLayout) - self.show() - - def scanDocument(self, action) : - doc = FreeCAD.ActiveDocument - print('Active') - print(doc) - if doc is not None : - #print(dir(doc)) - if hasattr(doc,'Objects') : - #print(doc.Objects) - #self.colorList = [] - for obj in doc.Objects : - #print(dir(obj)) - if hasattr(obj,'ViewObject') : - #print(dir(obj.ViewObject)) - if hasattr(obj.ViewObject,'isVisible') : - if obj.ViewObject.isVisible : - if hasattr(obj.ViewObject,'ShapeColor') : - colour = obj.ViewObject.ShapeColor - #print(colour) - colhex = '#'+''.join('{:02x}'.format(round(v*255)) \ - for v in colour) - if action == 1 : # Build Map - if not( colhex in self.colorDict) : - print(f'Add colour {colhex} {colour}') - if hasattr(obj,'material') : - material = obj.material - else : - material = None - self.addColour2Map(colour,colhex,material) - self.colorDict.update([(colhex,len(self.colorDict))]) - if action == 2 : # Update Object Material - if hasattr(obj,'Shape') : - mapIdx = self.colorDict[colhex] - print(f'Found {colhex} : id {mapIdx}') - print(obj.Label) - m = self.mapList.getMaterial(mapIdx) - # Only add - if not hasattr(obj,'material') : - obj.addProperty("App::PropertyEnumeration"\ - ,"material","GDML","Material") - obj.material = self.matList - # Ignore GDML objects which will have Proxy - if not hasattr(obj,'Proxy' ) : - obj.material=self.matList.index(m) - - def addColour2Map(self,c,hex,material) : - self.mapList.addEntry(QtGui.QColor(c[0]*255,c[1]*255,c[2]*255),hex,material) - - def lookupColour(self, col) : - print('Lookup Colour') - idx = self.colorList.index(col) - print(idx) - entry = self.mapList.vbox.itemAt(idx).widget() - print(entry) - mat = entry.hbox.itemAt(1).widget().currentText() - print(mat) - return mat - - def onCancel(self): - self.result = userCancelled - self.close() - - def onOk(self): - self.result = userOK - print('Set Materials') - self.scanDocument(2) - #self.close() - - def onNew(self) : - print('onNew') - - def onLoad(self) : - print('onLoad') - - def onSave(self) : - print('onSave') - # Save materials - from .exportGDML import exportMaterials - from .init_gui import joinDir - matGrp = FreeCAD.ActiveDocument.getObject('Materials') - if matGrp is not None : - exportMaterials(matGrp,joinDir('Resources/MapMaterials.xml')) - # Save Color Dictionary - f = open(joinDir('Resources/ColorDict.csv'),'w') - for key, value in self.colorDict.items(): - #print(f'key {key} value {value}') - #print(self.mapList.getMaterial(value)) - f.write(f'{key},{self.mapList.getMaterial(value)}\n') - f.close() - - def onScan(self) : - print('onScan') - self.scanDocument(1) - print('Update Layout') - self.coloursLayout.update() - - def getGDMLMaterials(self): - print('getGDMLMaterials') - matList = [] - doc = FreeCAD.activeDocument() - try : - materials = doc.Materials - geant4 = doc.Geant4 - g4Mats = doc.getObject('G4Materials') - - except : - from .importGDML import processXML - from .init_gui import joinDir - - print('Load Geant4 Materials XML') - processXML(doc,joinDir("Resources/Geant4Materials.xml")) - materials = doc.Materials - try : - if materials is not None : - for m in materials.OutList : - matList.append(m.Label) - #print(matList) - except : - pass - - try : - if g4Mats is not None : - for m in g4Mats.OutList : - matList.append(m.Label) - #print(matList) - except : - pass - - return matList + + def __init__(self, colhex): + super().__init__() + self.insert(colhex) + self.setReadOnly(True) + + +class GDMLColourMapEntry(QtGui.QWidget): + + def __init__(self, colour, colhex, material): + super().__init__() + print('Map Entry : '+str(colour)) + self.colour = colour + self.hbox = QtGui.QHBoxLayout() + self.hbox.addWidget(GDMLColour(colour)) + self.hbox.addWidget(GDMLColourHex(colhex)) + self.hbox.addWidget(material) + self.setLayout(self.hbox) + + def dataPicker(self): + print('DataPicker') + + +class GDMLColourMapList(QtGui.QScrollArea): + + def __init__(self, matList): + super().__init__() + # Scroll Area which contains the widgets, set as the centralWidget + # Widget that contains the collection of Vertical Box + self.widget = QtGui.QWidget() + self.matList = matList + # The Vertical Box that contains the Horizontal Boxes of labels and buttons + self.vbox = QtGui.QVBoxLayout() + self.widget.setLayout(self.vbox) + + # Scroll Area Properties + self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn) + self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) + self.setWidgetResizable(True) + self.setWidget(self.widget) + + def addEntry(self, colour, colhex, mat): + from .GDMLMaterials import GDMLMaterial + print('Add Entry') + matWidget = GDMLMaterial(self.matList, mat) + self.vbox.addWidget(GDMLColourMapEntry(colour, colhex, matWidget)) + + def getMaterial(self, index): + # print(dir(self.vbox)) + item = self.vbox.itemAt(index).widget() + # item.dumpObjectTree() + # cb = item.findChild(QtGui.QComboBox,'GDMLMaterial') + cb = item.findChildren(QtGui.QComboBox)[0] + m = cb.currentText() + print(m) + return(m) + + def setMaterial(self, index, mat): + item = self.vbox.itemAt(index).widget() + cb = item.findChildren(QtGui.QComboBox)[0] + matIndex = cb.findText(mat) + if matIndex != -1: + cb.setCurrentIndex(matIndex) + + +class GDMLColourMap(QtGui.QDialog): + def __init__(self, parent): + super(GDMLColourMap, self).__init__(parent, QtCore.Qt.Tool) + self.initUI() + + def initUI(self): + self.result = userCancelled + # create our window + # define window xLoc,yLoc,xDim,yDim + self.setGeometry(150, 450, 650, 550) + self.setWindowTitle("Map FreeCAD Colours to GDML Materials") + self.setMouseTracking(True) + self.buttonNew = QtGui.QPushButton(translate('GDML', 'New')) + self.buttonNew.clicked.connect(self.onNew) + self.buttonLoad = QtGui.QPushButton(translate('GDML', 'Load')) + self.buttonLoad.clicked.connect(self.onLoad) + self.buttonSave = QtGui.QPushButton(translate('GDML', 'Save')) + self.buttonSave.clicked.connect(self.onSave) + self.buttonScan = QtGui.QPushButton(translate('GDML', 'Scan')) + self.buttonScan.clicked.connect(self.onScan) + headerLayout = QtGui.QHBoxLayout() + headerLayout.addWidget(self.buttonNew) + headerLayout.addWidget(self.buttonLoad) + headerLayout.addWidget(self.buttonSave) + headerLayout.addWidget(self.buttonScan) + self.coloursLayout = QtGui.QGridLayout() + mainLayout = QtGui.QVBoxLayout(self) + mainLayout.addLayout(headerLayout) + mainLayout.addLayout(self.coloursLayout) + from .GDMLMaterials import getMaterialsList + self.matList = getMaterialsList() + self.mapList = GDMLColourMapList(self.matList) + self.colorDict = {} + self.scanDocument(1) + print(self.colorDict) + # for c in self.colorList : + # self.mapList.addEntry(QtGui.QColor(c[0]*255,c[1]*255,c[2]*255)) + # create Labels + self.label1 = self.mapList + self.coloursLayout.addWidget(self.label1, 0, 0) + # cancel button + cancelButton = QtGui.QPushButton('Cancel', self) + cancelButton.clicked.connect(self.onCancel) + cancelButton.setAutoDefault(True) + self.coloursLayout.addWidget(cancelButton, 2, 1) + + # OK button + okButton = QtGui.QPushButton('Set Materials', self) + okButton.clicked.connect(self.onOk) + self.coloursLayout.addWidget(okButton, 2, 0) + # now make the window visible + self.setLayout(mainLayout) + self.show() + + def scanDocument(self, action): + doc = FreeCAD.ActiveDocument + print('Active') + print(doc) + if doc is None: + return + # print(dir(doc)) + if hasattr(doc, 'Objects'): + # print(doc.Objects) + # self.colorList = [] + for obj in doc.Objects: + # print(dir(obj)) + if hasattr(obj, 'ViewObject'): + # print(dir(obj.ViewObject)) + if hasattr(obj.ViewObject, 'isVisible'): + if obj.ViewObject.isVisible: + if hasattr(obj.ViewObject, 'ShapeColor'): + colour = obj.ViewObject.ShapeColor + # print(colour) + colhex = '#'+''.join('{:02x}'.format(round(v*255)) + for v in colour) + if action == 1: # Build Map + if not(colhex in self.colorDict): + print(f'Add colour {colhex} {colour}') + if hasattr(obj, 'material'): + material = obj.material + else: + material = None + self.addColour2Map(colour, colhex, material) + self.colorDict.update([(colhex, len(self.colorDict))]) + if action == 2: # Update Object Material + if hasattr(obj, 'Shape'): + mapIdx = self.colorDict[colhex] + print(f'Found {colhex} : id {mapIdx}') + print(obj.Label) + m = self.mapList.getMaterial(mapIdx) + # Only add + if not hasattr(obj, 'material'): + obj.addProperty("App::PropertyEnumeration", + "material", "GDML", "Material") + obj.material = self.matList + # Ignore GDML objects which will have Proxy + if not hasattr(obj, 'Proxy'): + obj.material = self.matList.index(m) + + def addColour2Map(self, c, hex, material): + self.mapList.addEntry(QtGui.QColor(c[0]*255, c[1]*255, + c[2]*255), hex, material) + + def lookupColour(self, col): + print('Lookup Colour') + idx = self.colorList.index(col) + print(idx) + entry = self.mapList.vbox.itemAt(idx).widget() + print(entry) + mat = entry.hbox.itemAt(1).widget().currentText() + print(mat) + return mat + + def onCancel(self): + self.result = userCancelled + self.close() + + def onOk(self): + self.result = userOK + print('Set Materials') + self.scanDocument(2) + # self.close() + + def onNew(self): + print('onNew') + + def hex_to_rgb(self, value): + value = value.lstrip('#') + lv = len(value) + return tuple(int(value[i:i + lv // 3], 16) + for i in range(0, lv, lv // 3)) + + def onLoad(self): + import csv + from .importGDML import processXML, joinDir + print('onLoad') + processXML(FreeCAD.ActiveDocument, joinDir('Resources/MapMaterials.xml')) + # reset mapList + self.mapList = GDMLColourMapList(self.matList) + with open(joinDir('Resources/ColorDict.csv'), 'r') as file: + reader = csv.reader(file) + for i, row in enumerate(reader): + colhex = row[0] + colour = self.hex_to_rgb(colhex) + print(f'colour : {colour}') + material = row[1] + print(row) + print(row[1]) + idx = self.matList.index(row[1]) + self.addColour2Map(colour, colhex, material) + self.colorDict.update([(colhex, idx)]) + self.mapList.setMaterial(i, material) + + def onSave(self): + print('onSave') + # Save materials + from .exportGDML import exportMaterials + from .init_gui import joinDir + matGrp = FreeCAD.ActiveDocument.getObject('Materials') + if matGrp is not None: + exportMaterials(matGrp, joinDir('Resources/MapMaterials.xml')) + # Save Color Dictionary + f = open(joinDir('Resources/ColorDict.csv'), 'w') + for key, value in self.colorDict.items(): + print(f'key {key} value {value}') + print(self.mapList.getMaterial(value)) + f.write(f'{key},{self.mapList.getMaterial(value)}\n') + f.close() + + def onScan(self): + print('onScan') + self.scanDocument(1) + print('Update Layout') + self.coloursLayout.update() + + def getGDMLMaterials(self): + print('getGDMLMaterials') + matList = [] + doc = FreeCAD.activeDocument() + try: + materials = doc.Materials + geant4 = doc.Geant4 + g4Mats = doc.getObject('G4Materials') + + except: + from .importGDML import processXML + from .init_gui import joinDir + + print('Load Geant4 Materials XML') + processXML(doc, joinDir("Resources/Geant4Materials.xml")) + materials = doc.Materials + try: + if materials is not None: + for m in materials.OutList: + matList.append(m.Label) + # print(matList) + except: + pass + + try: + if g4Mats is not None: + for m in g4Mats.OutList: + matList.append(m.Label) + # print(matList) + except: + pass + + return matList # Class definitions @@ -334,6 +377,6 @@ def getGDMLMaterials(self): # Constant definitions global userCancelled, userOK -userCancelled = "Cancelled" -userOK = "OK" +userCancelled = "Cancelled" +userOK = "OK" diff --git a/freecad/gdml/GDMLCommands.py b/freecad/gdml/GDMLCommands.py index 4f9cb00c9..3e39a30a4 100644 --- a/freecad/gdml/GDMLCommands.py +++ b/freecad/gdml/GDMLCommands.py @@ -1,29 +1,29 @@ -#************************************************************************** -#* * -#* Copyright (c) 2017 Keith Sloan * -#* (c) Dam Lambert 2020 * -#* * -#* 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 * -#* * -#* Acknowledgements : * -#* * -#************************************************************************** - -__title__="FreeCAD GDML Workbench - GUI Commands" +# ************************************************************************** +# * * +# * Copyright (c) 2017 Keith Sloan * +# * (c) Dam Lambert 2020 * +# * * +# * 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 * +# * * +# * Acknowledgements : * +# * * +# ************************************************************************** + +__title__ = "FreeCAD GDML Workbench - GUI Commands" __author__ = "Keith Sloan" __url__ = ["http://www.freecadweb.org"] @@ -31,12 +31,14 @@ This Script includes the GUI Commands of the GDML module ''' -import FreeCAD,FreeCADGui +import FreeCAD, FreeCADGui from PySide import QtGui, QtCore + if FreeCAD.GuiUp: try: _encoding = QtGui.QApplication.UnicodeUTF8 + def translate(context, text): "convenience function for Qt translator" return QtGui.QApplication.translate(context, text, None, _encoding) @@ -45,11 +47,12 @@ def translate(context, text): "convenience function for Qt translator" return QtGui.QApplication.translate(context, text, None) + class importPrompt(QtGui.QDialog): def __init__(self, *args): super(importPrompt, self).__init__() self.initUI() - + def initUI(self): importButton = QtGui.QPushButton('Import') importButton.clicked.connect(self.onImport) @@ -58,15 +61,15 @@ def initUI(self): # buttonBox = QtGui.QDialogButtonBox() buttonBox.setFixedWidth(400) - #buttonBox = Qt.QDialogButtonBox(QtCore.Qt.Vertical) + # buttonBox = Qt.QDialogButtonBox(QtCore.Qt.Vertical) buttonBox.addButton(importButton, QtGui.QDialogButtonBox.ActionRole) buttonBox.addButton(scanButton, QtGui.QDialogButtonBox.ActionRole) # mainLayout = QtGui.QVBoxLayout() mainLayout.addWidget(buttonBox) self.setLayout(mainLayout) - #self.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False) - # define window xLoc,yLoc,xDim,yDim + # self.setWindowFlag(QtCore.Qt.WindowCloseButtonHint, False) + # define window xLoc,yLoc,xDim,yDim self.setGeometry( 650, 650, 0, 50) self.setWindowTitle("Choose an Option ") self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) @@ -80,362 +83,426 @@ def onScan(self): self.retStatus = 2 self.close() -def getSelectedMaterial() : + +def getSelectedMaterial(): from .exportGDML import nameFromLabel from .GDMLObjects import GDMLmaterial list = FreeCADGui.Selection.getSelection() - if list is not None : - for obj in list : - if hasattr(obj,'Proxy') : - if isinstance(obj.Proxy,GDMLmaterial) == True : - return nameFromLabel(obj.Label) + if list is not None: + for obj in list: + if hasattr(obj, 'Proxy'): + if isinstance(obj.Proxy, GDMLmaterial) is True: + return nameFromLabel(obj.Label) return 0 -def getSelectedPM() : + +def getSelectedPM(): from .exportGDML import nameFromLabel from .GDMLObjects import GDMLmaterial objPart = None material = 0 list = FreeCADGui.Selection.getSelection() - if list is not None : - for obj in list : - if hasattr(obj,'Proxy') : - if isinstance(obj.Proxy,GDMLmaterial) == True and \ - material == 0 : - material = nameFromLabel(obj.Label) - - if obj.TypeId == 'App::Part' and objPart is None : + if list is not None: + for obj in list: + if hasattr(obj, 'Proxy'): + if isinstance(obj.Proxy, GDMLmaterial) is True and \ + material == 0: + material = nameFromLabel(obj.Label) + + if obj.TypeId == 'App::Part' and objPart is None: objPart = obj - if objPart is not None and material !=0 : + if objPart is not None and material != 0: return objPart, material return objPart, material -def createPartVol(obj) : + +def createPartVol(obj): # Create Part(GDML Vol) Shared with a number of Features LVname = 'LV-'+obj.Label - if hasattr(obj,'InList') : - if len(obj.InList) > 0 : - parent = obj.InList[0] - vol=parent.newObject("App::Part",LVname) - else : - vol=FreeCAD.ActiveDocument.addObject("App::Part",LVname) - return vol + if hasattr(obj, 'InList'): + if len(obj.InList) > 0: + parent = obj.InList[0] + vol = parent.newObject("App::Part", LVname) + else: + vol = FreeCAD.ActiveDocument.addObject("App::Part", LVname) + return vol return None + class ColourMapFeature: - def Activated(self): - from PySide import QtGui, QtCore - #import sys - from .GDMLColourMap import resetGDMLColourMap, showGDMLColourMap - - print('Add colour Map') - resetGDMLColourMap() - showGDMLColourMap() - return - - #myWidget = QtGui.QDockWidget() - #mainWin = FreeCADGui.getMainWindow() - #mainWin.addDockWidget(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.TopDockWidgetArea, \ - mainWin.addDockWidget(QtCore.Qt.LeftDockWidgetArea or QtCore.Qt.TopDockWidgetArea, \ - myWidget) - #mainWin.addDockWidget(Qt::LeftDockWidgetArea or Qt::TopDockWidgetArea, myWidget) - #myWidget.setObjectName("ColourMap") - #myWidget.resize(QtCore.QSize(300,100)) - #title = QtGui.QLabel("Colour Mapping to GDML Materials") - #title.setIndent(100) - #myWidget.setTitleBarWidget(title) - #label = QtGui.QLabel("Colour Mapping to GDML Materials",myWidget) - - def IsActive(self): - if FreeCAD.ActiveDocument is None: - return False - else: - return True - - def GetResources(self): - return {'Pixmap' : 'GDMLColourMapFeature', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDMLColourMapFeature',\ - 'Add Colour Map'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDMLColourMapFeature',\ - 'Add Colour Map')} - - -class GDMLSetColour(QtGui.QDialog) : - def __init__(self, selList): - super(GDMLSetColour, self).__init__() - self.SelList = selList - self.initUI() - - def initUI(self) : - from .GDMLMaterials import GDMLMaterial, getMaterialsList - - print('initUI') - self.setGeometry( 150, 150, 250, 250) - self.setWindowTitle("Set GDML Material") - self.setMouseTracking(True) - self.buttonSet = QtGui.QPushButton(translate('GDML','Set Material')) - self.buttonSet.clicked.connect(self.onSet) - self.matList = getMaterialsList() - self.material = GDMLMaterial(self.matList,None) - mainLayout = QtGui.QVBoxLayout() - mainLayout.addWidget(self.material) - mainLayout.addWidget(self.buttonSet) - self.setLayout(mainLayout) - self.show() - - def onSet(self) : - mat = self.material.getItem() - print(f'Set Material {mat}') - for sel in self.SelList : - obj = sel.Object - if hasattr(obj,'material') : - obj.material = mat - else : - obj.addProperty("App::PropertyEnumeration","material", \ - "GDML","Material") - obj.material = self.matList - obj.material = self.matList.index(mat) + def Activated(self): + from PySide import QtGui, QtCore + # import sys + from .GDMLColourMap import resetGDMLColourMap, showGDMLColourMap + + print('Add colour Map') + resetGDMLColourMap() + showGDMLColourMap() + return + + # myWidget = QtGui.QDockWidget() + # mainWin = FreeCADGui.getMainWindow() + # mainWin.addDockWidget(QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.TopDockWidgetArea, \ + mainWin.addDockWidget(QtCore.Qt.LeftDockWidgetArea or QtCore.Qt.TopDockWidgetArea, \ + myWidget) + # mainWin.addDockWidget(Qt::LeftDockWidgetArea or Qt::TopDockWidgetArea, myWidget) + # myWidget.setObjectName("ColourMap") + # myWidget.resize(QtCore.QSize(300,100)) + # title = QtGui.QLabel("Colour Mapping to GDML Materials") + # title.setIndent(100) + # myWidget.setTitleBarWidget(title) + # label = QtGui.QLabel("Colour Mapping to GDML Materials",myWidget) + + def IsActive(self): + if FreeCAD.ActiveDocument is None: + return False + else: + return True + + def GetResources(self): + return {'Pixmap': 'GDMLColourMapFeature', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDMLColourMapFeature', + 'Add Colour Map'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('GDMLColourMapFeature', + 'Add Colour Map')} + + +class GDMLSetMaterial(QtGui.QDialog): + def __init__(self, selList): + super(GDMLSetMaterial, self).__init__() + self.SelList = selList + self.initUI() + + def initUI(self): + from .GDMLMaterials import GDMLMaterial, getGroupedMaterials + + print('initUI') + self.setGeometry(150, 150, 250, 250) + self.setWindowTitle("Set GDML Material") + self.setMouseTracking(True) + self.buttonSet = QtGui.QPushButton(translate('GDML', 'Set Material')) + self.buttonSet.clicked.connect(self.onSet) + self.groupedMaterials = getGroupedMaterials() # this build, then returns all materials + self.groupsCombo = QtGui.QComboBox() + groups = [group for group in self.groupedMaterials] + self.groupsCombo.addItems(groups) + self.groupsCombo.currentIndexChanged.connect(self.groupChanged) + self.materialComboBox = QtGui.QComboBox() + self.materialComboBox.addItems(self.groupedMaterials[groups[0]]) + self.matList = [] + for group in self.groupedMaterials: + self.matList += self.groupedMaterials[group] + self.completer = QtGui.QCompleter(self.matList, self) + self.completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive) + self.materialComboBox.setCompleter(self.completer) + self.materialComboBox.setEditable(True) + self.materialComboBox.currentTextChanged.connect(self.materialChanged) + self.lineedit = QtGui.QLineEdit() + self.lineedit.setCompleter(self.completer) + self.completer.activated.connect(self.completionActivated) + # self.materialComboBox.setEditable(False) + combosLayout = QtGui.QHBoxLayout() + combosLayout.addWidget(self.groupsCombo) + combosLayout.addWidget(self.materialComboBox) + mainLayout = QtGui.QVBoxLayout() + mainLayout.addWidget(self.lineedit) + mainLayout.addItem(combosLayout) + mainLayout.addWidget(self.buttonSet) + self.setLayout(mainLayout) + obj = self.SelList[0].Object + if hasattr(obj, 'material'): + mat = obj.material + self.lineedit.setText(mat) + self.setMaterial(mat) + self.show() + + def setMaterial(self, text): + from .GDMLObjects import GroupedMaterials + for i, group in enumerate(GroupedMaterials): + if text in GroupedMaterials[group]: + self.groupsCombo.blockSignals(True) + self.groupsCombo.setCurrentIndex(i) + self.groupsCombo.blockSignals(False) + self.groupChanged(i) + self.materialComboBox.blockSignals(True) + self.materialComboBox.setCurrentText(text) + self.materialComboBox.blockSignals(False) + + def completionActivated(self, text): + self.setMaterial(text) + + def groupChanged(self, index): + from .GDMLObjects import GroupedMaterials + self.materialComboBox.blockSignals(True) + self.materialComboBox.clear() + group = self.groupsCombo.currentText() + self.materialComboBox.addItems(GroupedMaterials[group]) + self.materialComboBox.blockSignals(False) + + def materialChanged(self, text): + self.lineedit.setText(text) + + def onSet(self): + # mat = self.materialComboBox.currentText() + mat = self.lineedit.text() + if mat not in self.matList: + print(f'Material {mat} not defined') + return + + print(f'Set Material {mat}') + for sel in self.SelList: + obj = sel.Object + if hasattr(obj, 'material'): + obj.material = mat + else: + obj.addProperty("App::PropertyEnumeration", "material", + "GDML", "Material") + obj.material = self.matList + obj.material = self.matList.index(mat) class SetMaterialFeature: - def Activated(self): - from PySide import QtGui, QtCore - - print('Add SetMaterial') - cnt = 0 - sel = FreeCADGui.Selection.getSelectionEx() - #print(sel) - set = [] - for s in sel : - #print(s) - #print(dir(s)) - if hasattr(s.Object,'Shape') : - cnt += 1 - set.append(s) - if cnt > 0 : - dialog = GDMLSetColour(set) - dialog.exec_() - return - - def IsActive(self): - if FreeCAD.ActiveDocument is None: - return False - else: - return True - - def GetResources(self): - return {'Pixmap' : 'GDML_SetMaterial', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDML_SetMaterial',\ - 'Set Material'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDML_SetMaterial',\ - 'Set Material')} - -class BooleanCutFeature : - - #def IsActive(self): + def Activated(self): + from PySide import QtGui, QtCore + + print('Add SetMaterial') + cnt = 0 + sel = FreeCADGui.Selection.getSelectionEx() + # print(sel) + set = [] + for s in sel: + # print(s) + # print(dir(s)) + if hasattr(s.Object, 'Shape'): + cnt += 1 + set.append(s) + if cnt > 0: + dialog = GDMLSetMaterial(set) + dialog.exec_() + return + + def IsActive(self): + if FreeCAD.ActiveDocument is None: + return False + else: + return True + + def GetResources(self): + return {'Pixmap': 'GDML_SetMaterial', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDML_SetMaterial', + 'Set Material'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('GDML_SetMaterial', + 'Set Material')} + + +class BooleanCutFeature: + + # def IsActive(self): # return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0 def Activated(self): - import Part sel = FreeCADGui.Selection.getSelectionEx() - if len(sel) == 2 : - print(sel) - selObj = 'Gui::SelectionObject' - if sel[0].TypeId == selObj and sel[1].TypeId == selObj : - if sel[0].Object.TypeId == 'App::Part' and \ - sel[1].Object.TypeId == 'App::Part' : - print('Boolean Cut') - if len(sel[0].Object.InList) > 0 : - parent = sel[0].Object.InList[0] - print('Parent : '+parent.Label) - baseVol = sel[0].Object - print('Base Vol : '+baseVol.Label) - toolVol = sel[1].Object - print('Tool Vol : '+toolVol.Label) - print(sel[0].Object.OutList) - base = sel[0].Object.OutList[-1] - print('Base : '+base.Label) - tool = sel[1].Object.OutList[-1] - print('Tool : '+tool.Label) - print('Remove Base') - baseVol.removeObject(base) - print('Adjust Base Links') - base.adjustRelativeLinks(baseVol) - toolVol.removeObject(tool) - tool.adjustRelativeLinks(toolVol) - boolVol = parent.newObject('App::Part','Bool-Cut') - boolVol.addObject(base) - boolVol.addObject(tool) - boolObj = boolVol.newObject('Part::Cut','Cut') - boolObj.Placement = sel[0].Object.Placement - boolObj.Base = base - boolObj.Tool = tool - boolObj.Tool.Placement.Base = sel[1].Object.Placement.Base \ - - sel[0].Object.Placement.Base - boolObj.Tool.setEditorMode('Placement',0) - print('Remove Base Vol') - FreeCAD.ActiveDocument.removeObject(baseVol.Label) - FreeCAD.ActiveDocument.removeObject(toolVol.Label) - boolObj.recompute() - else : + if len(sel) == 2: + print(sel) + selObj = 'Gui::SelectionObject' + if sel[0].TypeId == selObj and sel[1].TypeId == selObj: + if sel[0].Object.TypeId == 'App::Part' and \ + sel[1].Object.TypeId == 'App::Part': + print('Boolean Cut') + if len(sel[0].Object.InList) > 0: + parent = sel[0].Object.InList[0] + print('Parent : '+parent.Label) + baseVol = sel[0].Object + print('Base Vol : '+baseVol.Label) + toolVol = sel[1].Object + print('Tool Vol : '+toolVol.Label) + print(sel[0].Object.OutList) + base = sel[0].Object.OutList[-1] + print('Base : '+base.Label) + tool = sel[1].Object.OutList[-1] + print('Tool : '+tool.Label) + print('Remove Base') + baseVol.removeObject(base) + print('Adjust Base Links') + base.adjustRelativeLinks(baseVol) + toolVol.removeObject(tool) + tool.adjustRelativeLinks(toolVol) + boolVol = parent.newObject('App::Part', 'Bool-Cut') + boolVol.addObject(base) + boolVol.addObject(tool) + boolObj = boolVol.newObject('Part::Cut', 'Cut') + boolObj.Placement = sel[0].Object.Placement + boolObj.Base = base + boolObj.Tool = tool + boolObj.Tool.Placement.Base = sel[1].Object.Placement.Base \ + - sel[0].Object.Placement.Base + boolObj.Tool.setEditorMode('Placement', 0) + print('Remove Base Vol') + FreeCAD.ActiveDocument.removeObject(baseVol.Label) + FreeCAD.ActiveDocument.removeObject(toolVol.Label) + boolObj.recompute() + else: print('No Parent Volume/Part') def IsActive(self): if FreeCAD.ActiveDocument is None: - return False + return False else: - return True + return True def GetResources(self): - return {'Pixmap' : 'GDML_Cut', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('gdmlBooleanFeature',\ - 'GDML Cut'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('gdmlBooleanFeature',\ - 'GDML Cut')} + return {'Pixmap': 'GDML_Cut', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('gdmlBooleanFeature', + 'GDML Cut'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('gdmlBooleanFeature', + 'GDML Cut')} + -class BooleanIntersectionFeature : +class BooleanIntersectionFeature: - #def IsActive(self): + # def IsActive(self): # return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0 def Activated(self): import Part sel = FreeCADGui.Selection.getSelectionEx() - if len(sel) == 2 : - print(sel) - selObj = 'Gui::SelectionObject' - if sel[0].TypeId == selObj and sel[1].TypeId == selObj : - if sel[0].Object.TypeId == 'App::Part' and \ - sel[1].Object.TypeId == 'App::Part' : - print('Boolean Intersection') - if len(sel[0].Object.InList) > 0 : - parent = sel[0].Object.InList[0] - print('Parent : '+parent.Label) - baseVol = sel[0].Object - print('Base Vol : '+baseVol.Label) - toolVol = sel[1].Object - print('Tool Vol : '+toolVol.Label) - baseVol = sel[0].Object - print(sel[0].Object.OutList) - base = sel[0].Object.OutList[-1] - print('Base : '+base.Label) - tool = sel[1].Object.OutList[-1] - print('Tool : '+tool.Label) - print('Remove Base') - baseVol.removeObject(base) - print('Adjust Base Links') - base.adjustRelativeLinks(baseVol) - toolVol.removeObject(tool) - tool.adjustRelativeLinks(toolVol) - boolVol = parent.newObject('App::Part','Bool-Intersection') - boolVol.addObject(base) - boolVol.addObject(tool) - boolObj = boolVol.newObject('Part::Common','Common') - boolObj.Placement = sel[0].Object.Placement - boolObj.Base = base - boolObj.Tool = tool - boolObj.Tool.Placement.Base = sel[1].Object.Placement.Base \ - - sel[0].Object.Placement.Base - boolObj.Tool.setEditorMode('Placement',0) - FreeCAD.ActiveDocument.removeObject(baseVol.Label) - FreeCAD.ActiveDocument.removeObject(toolVol.Label) - boolObj.recompute() - else : - print('No Parent Volume/Part') + if len(sel) == 2: + print(sel) + selObj = 'Gui::SelectionObject' + if sel[0].TypeId == selObj and sel[1].TypeId == selObj: + if sel[0].Object.TypeId == 'App::Part' and \ + sel[1].Object.TypeId == 'App::Part' : + print('Boolean Intersection') + if len(sel[0].Object.InList) > 0: + parent = sel[0].Object.InList[0] + print('Parent : '+parent.Label) + baseVol = sel[0].Object + print('Base Vol : '+baseVol.Label) + toolVol = sel[1].Object + print('Tool Vol : '+toolVol.Label) + baseVol = sel[0].Object + print(sel[0].Object.OutList) + base = sel[0].Object.OutList[-1] + print('Base : '+base.Label) + tool = sel[1].Object.OutList[-1] + print('Tool : '+tool.Label) + print('Remove Base') + baseVol.removeObject(base) + print('Adjust Base Links') + base.adjustRelativeLinks(baseVol) + toolVol.removeObject(tool) + tool.adjustRelativeLinks(toolVol) + boolVol = parent.newObject('App::Part', 'Bool-Intersection') + boolVol.addObject(base) + boolVol.addObject(tool) + boolObj = boolVol.newObject('Part::Common', 'Common') + boolObj.Placement = sel[0].Object.Placement + boolObj.Base = base + boolObj.Tool = tool + boolObj.Tool.Placement.Base = sel[1].Object.Placement.Base \ + - sel[0].Object.Placement.Base + boolObj.Tool.setEditorMode('Placement', 0) + FreeCAD.ActiveDocument.removeObject(baseVol.Label) + FreeCAD.ActiveDocument.removeObject(toolVol.Label) + boolObj.recompute() + else: + print('No Parent Volume/Part') def IsActive(self): if FreeCAD.ActiveDocument is None: - return False + return False else: - return True + return True def GetResources(self): - return {'Pixmap' : 'GDML_Intersection', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('gdmlBooleanFeature',\ - 'GDML Intersection'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('gdmlBooleanFeature',\ - 'GDML Intersection')} + return {'Pixmap': 'GDML_Intersection', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('gdmlBooleanFeature', + 'GDML Intersection'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('gdmlBooleanFeature', + 'GDML Intersection')} + -class BooleanUnionFeature : +class BooleanUnionFeature: - #def IsActive(self): + # def IsActive(self): # return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0 def Activated(self): import Part sel = FreeCADGui.Selection.getSelectionEx() - if len(sel) == 2 : - print(sel) - selObj = 'Gui::SelectionObject' - if sel[0].TypeId == selObj and sel[1].TypeId == selObj : - if sel[0].Object.TypeId == 'App::Part' and \ - sel[1].Object.TypeId == 'App::Part' : - print('Boolean Union') - if len(sel[0].Object.InList) > 0 : - print(sel[0].Object.InList) - parent = sel[0].Object.InList[0] - print('Parent : '+parent.Label) - baseVol = sel[0].Object - print('Base Vol : '+baseVol.Label) - toolVol = sel[1].Object - print('Tool Vol : '+toolVol.Label) - baseVol = sel[0].Object - print(f'Base OutList {sel[0].Object.OutList}') - for o in sel[0].Object.OutList : - print(o.Label) - print(f'Tool OutList {sel[1].Object.OutList}') - for o in sel[1].Object.OutList : - print(o.Label) - print(f'True Base {sel[0].Object.OutList[-1].Label}') - base = sel[0].Object.OutList[-1] - print('Base : '+base.Label) - print(f'True Tool {sel[1].Object.OutList[-1].Label}') - tool = sel[1].Object.OutList[-1] - print('Tool : '+tool.Label) - print('Remove Base') - baseVol.removeObject(base) - print('Adjust Base Links') - base.adjustRelativeLinks(baseVol) - toolVol.removeObject(tool) - tool.adjustRelativeLinks(toolVol) - boolVol = parent.newObject('App::Part','Bool-Union') - boolVol.addObject(base) - boolVol.addObject(tool) - boolObj = boolVol.newObject('Part::Fuse','Union') - boolObj.Placement = sel[0].Object.Placement - boolObj.Base = base - boolObj.Tool = tool - boolObj.Tool.Placement.Base = sel[1].Object.Placement.Base \ - - sel[0].Object.Placement.Base - boolObj.Tool.setEditorMode('Placement',0) - FreeCAD.ActiveDocument.removeObject(baseVol.Label) - FreeCAD.ActiveDocument.removeObject(toolVol.Label) - boolObj.recompute() - else : - print('No Parent Volume') + if len(sel) == 2: + print(sel) + selObj = 'Gui::SelectionObject' + if sel[0].TypeId == selObj and sel[1].TypeId == selObj: + if sel[0].Object.TypeId == 'App::Part' and \ + sel[1].Object.TypeId == 'App::Part': + print('Boolean Union') + if len(sel[0].Object.InList) > 0: + print(sel[0].Object.InList) + parent = sel[0].Object.InList[0] + print('Parent : '+parent.Label) + baseVol = sel[0].Object + print('Base Vol : '+baseVol.Label) + toolVol = sel[1].Object + print('Tool Vol : '+toolVol.Label) + baseVol = sel[0].Object + print(f'Base OutList {sel[0].Object.OutList}') + for o in sel[0].Object.OutList: + print(o.Label) + print(f'Tool OutList {sel[1].Object.OutList}') + for o in sel[1].Object.OutList: + print(o.Label) + print(f'True Base {sel[0].Object.OutList[-1].Label}') + base = sel[0].Object.OutList[-1] + print('Base : '+base.Label) + print(f'True Tool {sel[1].Object.OutList[-1].Label}') + tool = sel[1].Object.OutList[-1] + print('Tool : '+tool.Label) + print('Remove Base') + baseVol.removeObject(base) + print('Adjust Base Links') + base.adjustRelativeLinks(baseVol) + toolVol.removeObject(tool) + tool.adjustRelativeLinks(toolVol) + boolVol = parent.newObject('App::Part', 'Bool-Union') + boolVol.addObject(base) + boolVol.addObject(tool) + boolObj = boolVol.newObject('Part::Fuse', 'Union') + boolObj.Placement = sel[0].Object.Placement + boolObj.Base = base + boolObj.Tool = tool + boolObj.Tool.Placement.Base = sel[1].Object.Placement.Base \ + - sel[0].Object.Placement.Base + boolObj.Tool.setEditorMode('Placement', 0) + FreeCAD.ActiveDocument.removeObject(baseVol.Label) + FreeCAD.ActiveDocument.removeObject(toolVol.Label) + boolObj.recompute() + else: + print('No Parent Volume') def IsActive(self): if FreeCAD.ActiveDocument is None: - return False + return False else: - return True + return True def GetResources(self): - return {'Pixmap' : 'GDML_Union', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('gdmlBooleanFeature',\ - 'GDML Union'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('gdmlBooleanFeature',\ - 'GDML Union')} + return {'Pixmap': 'GDML_Union', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('gdmlBooleanFeature', + 'GDML Union'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('gdmlBooleanFeature', + 'GDML Union')} + class BoxFeature: # def IsActive(self): @@ -444,221 +511,227 @@ class BoxFeature: def Activated(self): from .GDMLObjects import GDMLBox, ViewProvider objPart, material = getSelectedPM() - if objPart is None : - vol=FreeCAD.ActiveDocument.addObject("App::Part","LV-Box") - else : - vol=objPart.newObject("App::Part","LV-Box") - obj=vol.newObject("Part::FeaturePython","GDMLBox_Box") - #print("GDMLBox Object - added") + if objPart is None: + vol = FreeCAD.ActiveDocument.addObject("App::Part", "LV-Box") + else: + vol = objPart.newObject("App::Part", "LV-Box") + obj = vol.newObject("Part::FeaturePython", "GDMLBox_Box") + # print("GDMLBox Object - added") # obj, x, y, z, lunits, material - GDMLBox(obj,10.0,10.0,10.0,"mm",material) - #print("GDMLBox initiated") + GDMLBox(obj, 10.0, 10.0, 10.0, "mm", material) + # print("GDMLBox initiated") ViewProvider(obj.ViewObject) FreeCAD.ActiveDocument.recompute() FreeCADGui.SendMsgToActiveView("ViewFit") def IsActive(self): if FreeCAD.ActiveDocument is None: - return False + return False else: - return True + return True def GetResources(self): - return {'Pixmap' : 'GDMLBoxFeature', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDMLBoxFeature',\ - 'Box Object'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDMLBoxFeature',\ - 'Box Object')} + return {'Pixmap': 'GDMLBoxFeature', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDMLBoxFeature', + 'Box Object'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('GDMLBoxFeature', + 'Box Object')} + class ConeFeature: - #def IsActive(self): + # def IsActive(self): # return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0 def Activated(self): from .GDMLObjects import GDMLCone, ViewProvider objPart, material = getSelectedPM() - if objPart is None : - vol=FreeCAD.ActiveDocument.addObject("App::Part","LV-Cone") - else : - vol=objPart.newObject("App::Part","LV-Cone") - obj=vol.newObject("Part::FeaturePython","GDMLCone_Cone") - #print("GDMLCone Object - added") + if objPart is None: + vol = FreeCAD.ActiveDocument.addObject("App::Part", "LV-Cone") + else: + vol = objPart.newObject("App::Part", "LV-Cone") + obj = vol.newObject("Part::FeaturePython", "GDMLCone_Cone") + # print("GDMLCone Object - added") # obj,rmin1,rmax1,rmin2,rmax2,z,startphi,deltaphi,aunit,lunits,material - GDMLCone(obj,1,3,4,7,10.0,0,2,"rads","mm",material) - #print("GDMLCone initiated") + GDMLCone(obj, 1, 3, 4, 7, 10.0, 0, 2, "rads", "mm", material) + # print("GDMLCone initiated") ViewProvider(obj.ViewObject) - #print("GDMLCone ViewProvided - added") + # print("GDMLCone ViewProvided - added") FreeCAD.ActiveDocument.recompute() FreeCADGui.SendMsgToActiveView("ViewFit") def IsActive(self): if FreeCAD.ActiveDocument is None: - return False + return False else: - return True + return True def GetResources(self): - return {'Pixmap' : 'GDMLConeFeature', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDMLConeFeature',\ - 'Cone Object'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDMLConeFeature',\ - 'Cone Object')} + return {'Pixmap': 'GDMLConeFeature', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDMLConeFeature', + 'Cone Object'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('GDMLConeFeature', + 'Cone Object')} + class EllispoidFeature: - #def IsActive(self): + # def IsActive(self): # return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0 def Activated(self): from .GDMLObjects import GDMLEllipsoid, ViewProvider objPart, material = getSelectedPM() - if objPart is None : - vol=FreeCAD.ActiveDocument.addObject("App::Part","LV-Ellipsoid") - else : - vol=objPart.newObject("App::Part","LV-Ellipsoid") - obj=vol.newObject("Part::FeaturePython","GDMLEllipsoid_Ellipsoid") - #print("GDMLEllipsoid Object - added") + if objPart is None: + vol = FreeCAD.ActiveDocument.addObject("App::Part", "LV-Ellipsoid") + else: + vol = objPart.newObject("App::Part", "LV-Ellipsoid") + obj = vol.newObject("Part::FeaturePython", "GDMLEllipsoid_Ellipsoid") + # print("GDMLEllipsoid Object - added") # obj,ax, by, cz, zcut1, zcut2, lunit,material - GDMLEllipsoid(obj,10,20,30,0,0,"mm",material) - #print("GDMLEllipsoid initiated") + GDMLEllipsoid(obj, 10, 20, 30, 0, 0, "mm", material) + # print("GDMLEllipsoid initiated") ViewProvider(obj.ViewObject) - #print("GDMLEllipsoid ViewProvided - added") + # print("GDMLEllipsoid ViewProvided - added") FreeCAD.ActiveDocument.recompute() FreeCADGui.SendMsgToActiveView("ViewFit") def IsActive(self): if FreeCAD.ActiveDocument is None: - return False + return False else: - return True + return True def GetResources(self): - return {'Pixmap' : 'GDMLEllipsoidFeature', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDMLEllipsoidFeature',\ - 'Ellipsoid Object'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDMLEllipsoidFeature',\ - 'Ellipsoid Object')} + return {'Pixmap': 'GDMLEllipsoidFeature', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDMLEllipsoidFeature', + 'Ellipsoid Object'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('GDMLEllipsoidFeature', + 'Ellipsoid Object')} + class ElliTubeFeature: - #def IsActive(self): + # def IsActive(self): # return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0 def Activated(self): from .GDMLObjects import GDMLElTube, ViewProvider objPart, material = getSelectedPM() - if objPart is None : - vol=FreeCAD.ActiveDocument.addObject("App::Part","LV-EllipticalTube") - else : - vol=objPart.newObject("App::Part","LV-EllipticalTube") - obj=vol.newObject("Part::FeaturePython","GDMLElTube_Eltube") - #print("GDMLElTube Object - added") + if objPart is None: + vol = FreeCAD.ActiveDocument.addObject("App::Part", "LV-EllipticalTube") + else: + vol = objPart.newObject("App::Part", "LV-EllipticalTube") + obj = vol.newObject("Part::FeaturePython", "GDMLElTube_Eltube") + # print("GDMLElTube Object - added") # obj,dx, dy, dz, lunit, material - GDMLElTube(obj,10,20,30,"mm",material) - #print("GDMLElTube initiated") + GDMLElTube(obj, 10, 20, 30, "mm", material) + # print("GDMLElTube initiated") ViewProvider(obj.ViewObject) - #print("GDMLElTube ViewProvided - added") + # print("GDMLElTube ViewProvided - added") FreeCAD.ActiveDocument.recompute() FreeCADGui.SendMsgToActiveView("ViewFit") def IsActive(self): if FreeCAD.ActiveDocument is None: - return False + return False else: - return True + return True def GetResources(self): - return {'Pixmap' : 'GDMLElTubeFeature', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDMLElTubeFeature',\ - 'ElTube Object'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDMLElTubeFeature',\ - 'ElTube Object')} + return {'Pixmap': 'GDMLElTubeFeature', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDMLElTubeFeature', + 'ElTube Object'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('GDMLElTubeFeature', + 'ElTube Object')} + class SphereFeature: - #def IsActive(self): + # def IsActive(self): # return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0 def Activated(self): from .GDMLObjects import GDMLSphere, ViewProvider objPart, material = getSelectedPM() - #print(objPart) - #print(material) - if objPart is None : - vol=FreeCAD.ActiveDocument.addObject("App::Part","LV-Sphere") - else : - vol=objPart.newObject("App::Part","LV-Sphere") - obj=vol.newObject("Part::FeaturePython","GDMLSphere_Sphere") - #print("GDMLSphere Object - added") + # print(objPart) + # print(material) + if objPart is None: + vol = FreeCAD.ActiveDocument.addObject("App::Part", "LV-Sphere") + else: + vol = objPart.newObject("App::Part", "LV-Sphere") + obj = vol.newObject("Part::FeaturePython", "GDMLSphere_Sphere") + # print("GDMLSphere Object - added") # obj, rmin, rmax, startphi, deltaphi, starttheta, deltatheta, # aunit, lunits, material - GDMLSphere(obj,10.0, 20.0, 0.0, 2.02, 0.0, 2.02,"rad","mm",material) - #print("GDMLSphere initiated") + GDMLSphere(obj, 10.0, 20.0, 0.0, 2.02, 0.0, 2.02, "rad", "mm", material) + # print("GDMLSphere initiated") ViewProvider(obj.ViewObject) - #print("GDMLSphere ViewProvided - added") + # print("GDMLSphere ViewProvided - added") FreeCAD.ActiveDocument.recompute() FreeCADGui.SendMsgToActiveView("ViewFit") def IsActive(self): if FreeCAD.ActiveDocument is None: - return False + return False else: - return True + return True def GetResources(self): - return {'Pixmap' : 'GDMLSphereFeature', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDMLSphereFeature',\ - 'Sphere Object'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDMLSphereFeature',\ - 'Sphere Object')} + return {'Pixmap': 'GDMLSphereFeature', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDMLSphereFeature', + 'Sphere Object'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('GDMLSphereFeature', + 'Sphere Object')} + class TorusFeature: - #def IsActive(self): + # def IsActive(self): # return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0 def Activated(self): from .GDMLObjects import GDMLTorus, ViewProvider objPart, material = getSelectedPM() - if objPart is None : - vol=FreeCAD.ActiveDocument.addObject("App::Part","LV-Torus") - else : - vol=objPart.newObject("App::Part","LV-Torus") - myTorus=vol.newObject("Part::FeaturePython","GDMLTorus_Torus") - GDMLTorus(myTorus,10,50,50,10,360,"deg","mm",material) - if FreeCAD.GuiUp : - myTorus.ViewObject.Visibility = True - ViewProvider(myTorus.ViewObject) - - FreeCAD.ActiveDocument.recompute() - FreeCADGui.SendMsgToActiveView("ViewFit") - + if objPart is None: + vol = FreeCAD.ActiveDocument.addObject("App::Part", "LV-Torus") + else: + vol = objPart.newObject("App::Part", "LV-Torus") + myTorus = vol.newObject("Part::FeaturePython", "GDMLTorus_Torus") + GDMLTorus(myTorus, 10, 50, 50, 10, 360, "deg", "mm", material) + if FreeCAD.GuiUp: + myTorus.ViewObject.Visibility = True + ViewProvider(myTorus.ViewObject) + + FreeCAD.ActiveDocument.recompute() + FreeCADGui.SendMsgToActiveView("ViewFit") + def IsActive(self): if FreeCAD.ActiveDocument is None: - return False + return False else: - return True + return True def GetResources(self): - return {'Pixmap' : 'GDMLTorusFeature', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDMLTorusFeature',\ - 'Torus Object'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDMLTorusFeature',\ - 'Torus Object')} + return {'Pixmap': 'GDMLTorusFeature', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDMLTorusFeature', + 'Torus Object'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('GDMLTorusFeature', + 'Torus Object')} + class TrapFeature: - #def IsActive(self): + # def IsActive(self): # return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0 def Activated(self): from .GDMLObjects import GDMLTrap, ViewProvider objPart, material = getSelectedPM() - if objPart is None : - vol=FreeCAD.ActiveDocument.addObject("App::Part","LV-Trap") - else : - vol=objPart.newObject("App::Part","LV-Trap") - obj=vol.newObject("Part::FeaturePython","GDMLTrap_Trap") + if objPart is None: + vol = FreeCAD.ActiveDocument.addObject("App::Part", "LV-Trap") + else: + vol = objPart.newObject("App::Part", "LV-Trap") + obj = vol.newObject("Part::FeaturePython", "GDMLTrap_Trap") print("GDMLTrap Object - added") # obj z, theta, phi, x1, x2, x3, x4, y1, y2, # pAlp2, aunits, lunits, material - GDMLTrap(obj,10.0,0.0,0.0,6.0,6.0,6.0,6.0,7.0,7.0,0.0,"rad","mm", \ - material) + GDMLTrap(obj, 10.0, 0.0, 0.0, 6.0, 6.0, 6.0, 6.0, 7.0, 7.0, 0.0, + "rad", "mm", material) print("GDMLTrap initiated") ViewProvider(obj.ViewObject) print("GDMLTrap ViewProvided - added") @@ -667,99 +740,101 @@ def Activated(self): def IsActive(self): if FreeCAD.ActiveDocument is None: - return False + return False else: - return True + return True def GetResources(self): - return {'Pixmap' : 'GDMLTrapFeature', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDMLTrapFeature',\ - 'Trap Object'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDMLTrapFeature',\ - 'Trap Object')} + return {'Pixmap': 'GDMLTrapFeature', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDMLTrapFeature', + 'Trap Object'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('GDMLTrapFeature', + 'Trap Object')} class TubeFeature: - #def IsActive(self): + # def IsActive(self): # return FreeCADGui.Selection.countObjectsOfType('Part::Feature') > 0 def Activated(self): from .GDMLObjects import GDMLTube, ViewProvider objPart, material = getSelectedPM() - if objPart is None : - vol=FreeCAD.ActiveDocument.addObject("App::Part","LV-Tube") - else : - vol=objPart.newObject("App::Part","LV-Tube") - obj=vol.newObject("Part::FeaturePython","GDMLTube_Tube") - #print("GDMLTube Object - added") + if objPart is None: + vol = FreeCAD.ActiveDocument.addObject("App::Part", "LV-Tube") + else: + vol = objPart.newObject("App::Part", "LV-Tube") + obj = vol.newObject("Part::FeaturePython", "GDMLTube_Tube") + # print("GDMLTube Object - added") # obj, rmin, rmax, z, startphi, deltaphi, aunit, lunits, material - GDMLTube(obj,5.0,8.0,10.0,0.52,1.57,"rad","mm",material) - #print("GDMLTube initiated") + GDMLTube(obj, 5.0, 8.0, 10.0, 0.52, 1.57, "rad", "mm", material) + # print("GDMLTube initiated") ViewProvider(obj.ViewObject) - #print("GDMLTube ViewProvided - added") + # print("GDMLTube ViewProvided - added") FreeCAD.ActiveDocument.recompute() FreeCADGui.SendMsgToActiveView("ViewFit") def IsActive(self): if FreeCAD.ActiveDocument is None: - return False + return False else: - return True + return True def GetResources(self): - return {'Pixmap' : 'GDMLTubeFeature', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDMLTubeFeature',\ - 'Tube Object'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDMLTubeFeature',\ - 'Tube Object')} + return {'Pixmap': 'GDMLTubeFeature', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDMLTubeFeature', + 'Tube Object'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('GDMLTubeFeature', + 'Tube Object')} -class PolyHedraFeature : - - def Activated(self) : + +class PolyHedraFeature: + + def Activated(self): for obj in FreeCADGui.Selection.getSelection(): - #if len(obj.InList) == 0: # allowed only for for top level objects + # if len(obj.InList) == 0: # allowed only for for top level objects print('Action Poly') - if hasattr(obj,'Shape') : - print(obj.Shape.ShapeType) - if hasattr(obj.Shape,'Vertexes') : - numVert = len(obj.Shape.Vertexes) - print('Number of Vertex : '+str(numVert)) - print(obj.Shape.Vertexes) - if hasattr(obj.Shape,'Faces') : - print('Faces') - #print(dir(obj.Shape.Faces[0])) - print(obj.Shape.Faces) - planar = self.checkPlanar(obj.Shape.Faces) - print(planar) - if hasattr(obj.Shape,'Edges') : - print('Edges') - #print(dir(obj.Shape.Edges[0])) - print(obj.Shape.Edges) - - def checkPlanar(self,faces): + if hasattr(obj, 'Shape'): + print(obj.Shape.ShapeType) + if hasattr(obj.Shape, 'Vertexes'): + numVert = len(obj.Shape.Vertexes) + print('Number of Vertex : '+str(numVert)) + print(obj.Shape.Vertexes) + if hasattr(obj.Shape, 'Faces'): + print('Faces') + # print(dir(obj.Shape.Faces[0])) + print(obj.Shape.Faces) + planar = self.checkPlanar(obj.Shape.Faces) + print(planar) + if hasattr(obj.Shape, 'Edges'): + print('Edges') + # print(dir(obj.Shape.Edges[0])) + print(obj.Shape.Edges) + + def checkPlanar(self, faces): import Part print('Check Planar') - for f in faces : - if not isinstance(f.Surface, Part.Plane) : - return False + for f in faces: + if not isinstance(f.Surface, Part.Plane): + return False return True def GetResources(self): - return {'Pixmap' : 'GDML_Polyhedra', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDML_PolyGroup',\ - 'Poly Group'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDML_PolyGroup', \ - 'PolyHedra Selected Object')} - -class iField(QtGui.QWidget) : - def __init__(self,label,len,value,parent=None) : + return {'Pixmap': 'GDML_Polyhedra', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDML_PolyGroup', + 'Poly Group'), 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('GDML_PolyGroup', + 'PolyHedra Selected Object')} + + +class iField(QtGui.QWidget): + def __init__(self, label, len, value, parent=None): super(iField, self).__init__(parent) self.label = QtGui.QLabel(label) self.value = QtGui.QLineEdit() self.value.setMaxLength(len) - self.value.setGeometry(QtCore.QRect(10,20,25,15)) - self.value.setTextMargins(0,0,10,5) + self.value.setGeometry(QtCore.QRect(10, 20, 25, 15)) + self.value.setTextMargins(0, 0, 10, 5) self.value.setText(value) self.label.setBuddy(self.value) layout = QtGui.QHBoxLayout() @@ -767,13 +842,14 @@ def __init__(self,label,len,value,parent=None) : layout.addWidget(self.value) self.setLayout(layout) -class oField(QtGui.QWidget) : - def __init__(self,label,len, value,parent=None) : + +class oField(QtGui.QWidget): + def __init__(self, label, len, value, parent=None): super(oField, self).__init__(parent) self.label = QtGui.QLabel(label) self.value = QtGui.QLineEdit() self.value.setMaxLength(len) - self.value.setGeometry(QtCore.QRect(0,0,10,5)) + self.value.setGeometry(QtCore.QRect(0, 0, 10, 5)) self.value.setReadOnly(True) self.value.setText(value) self.label.setBuddy(self.value) @@ -782,60 +858,62 @@ def __init__(self,label,len, value,parent=None) : layout.addWidget(self.value) self.setLayout(layout) - def sizeHint(self) : - return(QtCore.QSize(10,5)) + def sizeHint(self): + return(QtCore.QSize(10, 5)) + class AddDecimateWidget(QtGui.QWidget): - def __init__(self, Obj,*args): - QtGui.QWidget.__init__(self,*args) - #bboxGroup = QtGui.QGroupBox('Objects Bounding Box') - #laybbox = QtGui.QHBoxLayout() - #laybbox.addWidget(QtGui.QLabel('Width : '+str(Shape.BoundBox.XLength))) - #laybbox.addWidget(QtGui.QLabel('Height : '+str(Shape.BoundBox.YLength))) - #laybbox.addWidget(QtGui.QLabel('Depth : '+str(Shape.BoundBox.ZLength) )) - #bboxGroup.setLayout(laybbox) - #maxl = int((Shape.BoundBox.XLength + Shape.BoundBox.YLength + \ + def __init__(self, Obj, *args): + QtGui.QWidget.__init__(self, *args) + # bboxGroup = QtGui.QGroupBox('Objects Bounding Box') + # laybbox = QtGui.QHBoxLayout() + # laybbox.addWidget(QtGui.QLabel('Width : '+str(Shape.BoundBox.XLength))) + # laybbox.addWidget(QtGui.QLabel('Height : '+str(Shape.BoundBox.YLength))) + # laybbox.addWidget(QtGui.QLabel('Depth : '+str(Shape.BoundBox.ZLength) )) + # bboxGroup.setLayout(laybbox) + # maxl = int((Shape.BoundBox.XLength + Shape.BoundBox.YLength + \ # Shape.BoundBox.ZLength) / 15) - self.type = QtGui.QComboBox() - #self.type.addItems(['sp4cerat','MeshLab','Blender']) + self.type = QtGui.QComboBox() + # self.type.addItems(['sp4cerat','MeshLab','Blender']) self.type.addItems(['sp4cerat']) - self.group1 = QtGui.QGroupBox('Decimate Reduction') - self.tolerance = iField('Tolerance',5,'5.0') - self.reduction = iField('Reduction',5,'0.8') + self.group1 = QtGui.QGroupBox('Decimate Reduction') + self.tolerance = iField('Tolerance', 5, '5.0') + self.reduction = iField('Reduction', 5, '0.8') self.parms1layout = QtGui.QHBoxLayout() self.parms1layout.addWidget(self.tolerance) self.parms1layout.addWidget(self.reduction) self.grpLay1 = QtGui.QVBoxLayout() self.grpLay1.addLayout(self.parms1layout) - self.buttonReduction = QtGui.QPushButton(translate('GDML','Decimate Reduction')) + self.buttonReduction = QtGui.QPushButton(translate('GDML', 'Decimate Reduction')) self.grpLay1.addWidget(self.buttonReduction) self.group1.setLayout(self.grpLay1) - self.group2 = QtGui.QGroupBox('Decimate to Size') - self.targetSize = iField('Target Size',5,'100') + self.group2 = QtGui.QGroupBox('Decimate to Size') + self.targetSize = iField('Target Size', 5, '100') self.grpLay2 = QtGui.QVBoxLayout() self.grpLay2.addWidget(self.targetSize) - self.buttonToSize = QtGui.QPushButton(translate('GDML','Decimate To Size')) + self.buttonToSize = QtGui.QPushButton(translate('GDML', 'Decimate To Size')) self.grpLay2.addWidget(self.buttonToSize) self.group2.setLayout(self.grpLay2) - self.Vlayout= QtGui.QVBoxLayout() + self.Vlayout = QtGui.QVBoxLayout() self.Vlayout.addWidget(self.type) self.Vlayout.addWidget(self.group1) self.Vlayout.addWidget(self.group2) self.setLayout(self.Vlayout) - self.setWindowTitle(translate('GDML','Decimate')) + self.setWindowTitle(translate('GDML', 'Decimate')) - def leaveEvent(self, event) : + def leaveEvent(self, event): print('Leave Event') - QtCore.QTimer.singleShot(0, lambda :FreeCADGui.Control.closeDialog()) + QtCore.QTimer.singleShot(0, lambda: FreeCADGui.Control.closeDialog()) def retranslateUi(self, widget=None): - self.buttonMesh.setText(translate('GDML','Decimate')) - self.setWindowTitle(translate('GDML','Decimate')) + self.buttonMesh.setText(translate('GDML', 'Decimate')) + self.setWindowTitle(translate('GDML', 'Decimate')) + class AddDecimateTask: def __init__(self, Obj): - self.obj = Obj + self.obj = Obj self.form = AddDecimateWidget(Obj) self.form.buttonReduction.clicked.connect(self.actionReduction) self.form.buttonToSize.clicked.connect(self.actionToSize) @@ -852,152 +930,153 @@ def isAllowedAlterView(self): def isAllowedAlterDocument(self): return True - def actionReduction(self) : - from .GmshUtils import TessellatedShape2Mesh + def actionReduction(self): + from .GmshUtils import TessellatedShape2Mesh print('Action Decimate Reduction : '+self.obj.Name) - #print(dir(self)) - if hasattr(self.obj,'Mesh') : - mesh = self.obj.Mesh - else : - mesh = TessellatedShape2Mesh(self.obj) - try : - tolerance = float(self.form.tolerance.value.text()) - reduction = float(self.form.reduction.value.text()) - print('Tolerance : '+str(tolerance)) - print('Reduction : '+str(reduction)) - mesh.decimate(tolerance,reduction) + # print(dir(self)) + if hasattr(self.obj, 'Mesh'): + mesh = self.obj.Mesh + else: + mesh = TessellatedShape2Mesh(self.obj) + try: + tolerance = float(self.form.tolerance.value.text()) + reduction = float(self.form.reduction.value.text()) + print('Tolerance : '+str(tolerance)) + print('Reduction : '+str(reduction)) + mesh.decimate(tolerance, reduction) except Exception as e: - print(e) + print(e) - #print(dir(self.obj)) - self.obj.Proxy.updateParams(mesh.Topology[0],mesh.Topology[1],False) + # print(dir(self.obj)) + self.obj.Proxy.updateParams(mesh.Topology[0], mesh.Topology[1], False) self.obj.recompute() self.obj.ViewObject.Visibility = True FreeCADGui.SendMsgToActiveView("ViewFit") print('Update Gui') FreeCADGui.updateGui() - def actionToSize(self) : - from .GmshUtils import TessellatedShape2Mesh + def actionToSize(self): + from .GmshUtils import TessellatedShape2Mesh print('Action Decimate To Size : '+self.obj.Name) print(dir(self)) - if hasattr(self.obj,'Mesh') : - mesh = self.obj.Mesh - else : - mesh = TessellatedShape2Mesh(self.obj) + if hasattr(self.obj, 'Mesh'): + mesh = self.obj.Mesh + else: + mesh = TessellatedShape2Mesh(self.obj) - try : - targetSize = int(self.form.targetSize.value.text()) - print('Target Size : '+str(targetSize)) - mesh.decimate(targetSize) + try: + targetSize = int(self.form.targetSize.value.text()) + print('Target Size : '+str(targetSize)) + mesh.decimate(targetSize) - except : - print('Invalid Float Values') + except: + print('Invalid Float Values') - def leaveEvent(self, event) : + def leaveEvent(self, event): print('Leave Event II') - def focusOutEvent(self, event) : + def focusOutEvent(self, event): print('Out of Focus II') -class DecimateFeature : - - def Activated(self) : - import Mesh - import MeshPart + +class DecimateFeature: + + def Activated(self): from .GDMLObjects import GDMLTessellated, GDMLTriangular, \ ViewProvider, ViewProviderExtension for obj in FreeCADGui.Selection.getSelection(): - #if len(obj.InList) == 0: # allowed only for for top level objects + # if len(obj.InList) == 0: # allowed only for for top level objects print('Action Decimate') - if self.isDecimatable(obj) : - if FreeCADGui.Control.activeDialog() == False : - print('Build panel for Decimate') - panel = AddDecimateTask(obj) - FreeCADGui.Control.showDialog(panel) - else : - print('Already an Active Task') + if self.isDecimatable(obj): + if FreeCADGui.Control.activeDialog() is False: + print('Build panel for Decimate') + panel = AddDecimateTask(obj) + FreeCADGui.Control.showDialog(panel) + else: + print('Already an Active Task') return - + def GetResources(self): - return {'Pixmap' : 'GDML_Decimate', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup',\ - 'Decimate Selected Object'), 'Decimate': \ - QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', \ - 'Decimate Selected Object')} - - def isDecimatable(self, obj) : - if hasattr(obj,'Proxy') : - print(obj.Proxy.Type) - if obj.Proxy.Type == 'GDMLGmshTessellated' or \ - obj.Proxy.Type == 'GDMLTessellated' : - return True - if hasattr(obj,'Mesh') : - return True + return {'Pixmap': 'GDML_Decimate', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', + 'Decimate Selected Object'), 'Decimate': + QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', + 'Decimate Selected Object')} + + def isDecimatable(self, obj): + if hasattr(obj, 'Proxy'): + print(obj.Proxy.Type) + if obj.Proxy.Type == 'GDMLGmshTessellated' or \ + obj.Proxy.Type == 'GDMLTessellated': + return True + if hasattr(obj, 'Mesh'): + return True return False + class AddTessellateWidget(QtGui.QWidget): - def __init__(self, Shape,*args): - QtGui.QWidget.__init__(self,*args) - bboxGroup = QtGui.QGroupBox('Objects Bounding Box') + def __init__(self, Shape, *args): + QtGui.QWidget.__init__(self, *args) + bboxGroup = QtGui.QGroupBox('Objects Bounding Box') laybbox = QtGui.QHBoxLayout() laybbox.addWidget(QtGui.QLabel('Width : '+str(Shape.BoundBox.XLength))) laybbox.addWidget(QtGui.QLabel('Height : '+str(Shape.BoundBox.YLength))) - laybbox.addWidget(QtGui.QLabel('Depth : '+str(Shape.BoundBox.ZLength) )) + laybbox.addWidget(QtGui.QLabel('Depth : '+str(Shape.BoundBox.ZLength))) bboxGroup.setLayout(laybbox) - maxl = int((Shape.BoundBox.XLength + Shape.BoundBox.YLength + \ + maxl = int((Shape.BoundBox.XLength + Shape.BoundBox.YLength + Shape.BoundBox.ZLength) / 15) - self.type = QtGui.QComboBox() - self.type.addItems(['Triangular','Quadrangular','Parallelograms']) - self.group = QtGui.QGroupBox('Mesh Characteristics') - self.maxLen = iField('Max Length',5,str(maxl)) - self.curveLen = iField('Curve Length',5,'10') - self.pointLen = iField('Length from Point',5,'10') - self.Vertex = oField('Vertex',6,'') - self.Facets = oField('Facets',6,'') - self.meshParmsLayout=QtGui.QGridLayout() - self.meshParmsLayout.addWidget(self.type,0,0) - self.meshParmsLayout.addWidget(self.maxLen,0,1) - self.meshParmsLayout.addWidget(self.curveLen,1,0) - self.meshParmsLayout.addWidget(self.pointLen,1,1) + self.type = QtGui.QComboBox() + self.type.addItems(['Triangular', 'Quadrangular', 'Parallelograms']) + self.group = QtGui.QGroupBox('Mesh Characteristics') + self.maxLen = iField('Max Length', 5, str(maxl)) + self.curveLen = iField('Curve Length', 5, '10') + self.pointLen = iField('Length from Point', 5, '10') + self.Vertex = oField('Vertex', 6, '') + self.Facets = oField('Facets', 6, '') + self.meshParmsLayout = QtGui.QGridLayout() + self.meshParmsLayout.addWidget(self.type, 0, 0) + self.meshParmsLayout.addWidget(self.maxLen, 0, 1) + self.meshParmsLayout.addWidget(self.curveLen, 1, 0) + self.meshParmsLayout.addWidget(self.pointLen, 1, 1) self.group.setLayout(self.meshParmsLayout) - self.buttonMesh = QtGui.QPushButton(translate('GDML','Mesh')) - layoutAction=QtGui.QHBoxLayout() + self.buttonMesh = QtGui.QPushButton(translate('GDML', 'Mesh')) + layoutAction = QtGui.QHBoxLayout() layoutAction.addWidget(self.buttonMesh) - self.Vlayout= QtGui.QVBoxLayout() + self.Vlayout = QtGui.QVBoxLayout() self.Vlayout.addWidget(bboxGroup) self.Vlayout.addWidget(self.group) self.Vlayout.addLayout(layoutAction) self.setLayout(self.Vlayout) - self.setWindowTitle(translate('GDML','Tessellate with Gmsh')) + self.setWindowTitle(translate('GDML', 'Tessellate with Gmsh')) - def leaveEvent(self, event) : + def leaveEvent(self, event): print('Leave Event') - #FreeCADGui.Control.closeDialog() - #closeDialog() - #QtCore.QMetaObject.invokeMethod(FreeCADGui.Control, 'closeDialog', QtCore.Qt.QueuedConnection) - #QtCore.QTimer.singleShot(0, FreeCADGui.Control, SLOT('closeDialog()')) - #QtCore.QTimer.singleShot(0, FreeCADGui.Control, QtCore.SLOT('closeDialog()')) - QtCore.QTimer.singleShot(0, lambda :FreeCADGui.Control.closeDialog()) + # FreeCADGui.Control.closeDialog() + # closeDialog() + # QtCore.QMetaObject.invokeMethod(FreeCADGui.Control, 'closeDialog', QtCore.Qt.QueuedConnection) + # QtCore.QTimer.singleShot(0, FreeCADGui.Control, SLOT('closeDialog()')) + # QtCore.QTimer.singleShot(0, FreeCADGui.Control, QtCore.SLOT('closeDialog()')) + QtCore.QTimer.singleShot(0, lambda: FreeCADGui.Control.closeDialog()) def retranslateUi(self, widget=None): - self.buttonMesh.setText(translate('GDML','Mesh')) - self.setWindowTitle(translate('GDML','Tessellate with Gmsh')) + self.buttonMesh.setText(translate('GDML', 'Mesh')) + self.setWindowTitle(translate('GDML', 'Tessellate with Gmsh')) + class AddTessellateTask: def __init__(self, Obj): - self.obj = Obj + self.obj = Obj self.tess = None self.form = AddTessellateWidget(Obj.Shape) self.form.buttonMesh.clicked.connect(self.actionMesh) - #self.form.buttonload.clicked.connect(self.loadelement) - #self.form.buttonsave.clicked.connect(self.saveelement) - #self.form.buttonrefresh.clicked.connect(self.refreshelement) + # self.form.buttonload.clicked.connect(self.loadelement) + # self.form.buttonsave.clicked.connect(self.saveelement) + # self.form.buttonrefresh.clicked.connect(self.refreshelement) def getStandardButtons(self): return int(QtGui.QDialogButtonBox.Close) @@ -1011,176 +1090,175 @@ def isAllowedAlterView(self): def isAllowedAlterDocument(self): return True - def processMesh(self, vertex, facets) : + def processMesh(self, vertex, facets): from .GDMLObjects import ViewProvider print('Update Tessellated Object') print(dir(self)) - print('Object Name ' +self.obj.Name) - print('Object Type ' +self.obj.TypeId) - if hasattr(self.obj,'Proxy') : - print('Proxy') - print(self.obj.Proxy.Type) - if self.obj.Proxy.Type == 'GDMLGmshTessellated' or \ - self.obj.Proxy.Type == 'GDMLTessellated' : - self.obj.Proxy.updateParams(vertex,facets,False) - #print(dir(self.form)) + print('Object Name ' + self.obj.Name) + print('Object Type ' + self.obj.TypeId) + if hasattr(self.obj, 'Proxy'): + print('Proxy') + print(self.obj.Proxy.Type) + if self.obj.Proxy.Type == 'GDMLGmshTessellated' or \ + self.obj.Proxy.Type == 'GDMLTessellated': + self.obj.Proxy.updateParams(vertex, facets, False) + # print(dir(self.form)) print('Vertex : '+str(len(vertex))) print('Facets : '+str(len(facets))) # Update Info of GDML Tessellated Object - if self.tess is not None : - print('Tesselated Name '+self.tess.Name) - print('Update parms : '+self.tess.Name) - if hasattr(self.tess,'Proxy') : # If GDML object has Proxy - print(dir(self.tess.Proxy)) - self.tess.Proxy.updateParams(vertex,facets,False) - else : - self.tess.updateParams(vertex,facets,False) - #print('Update parms : '+self.tess.Name) - #self.tess.updateParams(vertex,facets,False) - #self.form.Vertex.value.setText(QtCore.QString(len(vertex))) + if self.tess is not None: + print('Tesselated Name '+self.tess.Name) + print('Update parms : '+self.tess.Name) + if hasattr(self.tess, 'Proxy'): # If GDML object has Proxy + print(dir(self.tess.Proxy)) + self.tess.Proxy.updateParams(vertex, facets, False) + else: + self.tess.updateParams(vertex, facets, False) + # print('Update parms : '+self.tess.Name) + # self.tess.updateParams(vertex,facets,False) + # self.form.Vertex.value.setText(QtCore.QString(len(vertex))) self.form.Vertex.value.setText(str(len(vertex))) - #self.form.Facets.value.setText(QtCore.QString(len(facets))) + # self.form.Facets.value.setText(QtCore.QString(len(facets))) self.form.Facets.value.setText(str(len(facets))) - if FreeCAD.GuiUp : - if self.tess is not None : - self.obj.ViewObject.Visibility = False - ViewProvider(self.tess.ViewObject) - self.tess.ViewObject.DisplayMode = "Wireframe" - self.tess.recompute() - #FreeCAD.ActiveDocument.recompute() - else : - print('Recompute : '+self.obj.Name) - self.obj.recompute() - self.obj.ViewObject.Visibility = True - FreeCADGui.SendMsgToActiveView("ViewFit") - FreeCADGui.updateGui() - - def actionMesh(self) : + if FreeCAD.GuiUp: + if self.tess is not None: + self.obj.ViewObject.Visibility = False + ViewProvider(self.tess.ViewObject) + self.tess.ViewObject.DisplayMode = "Wireframe" + self.tess.recompute() + # FreeCAD.ActiveDocument.recompute() + else: + print('Recompute : '+self.obj.Name) + self.obj.recompute() + self.obj.ViewObject.Visibility = True + FreeCADGui.SendMsgToActiveView("ViewFit") + FreeCADGui.updateGui() + + def actionMesh(self): from .GmshUtils import initialize, meshObject, \ getVertex, getFacets, getMeshLen, printMeshInfo, printMyInfo from .GDMLObjects import GDMLGmshTessellated, GDMLTriangular print('Action Gmsh : '+self.obj.Name) initialize() - typeDict = {0:6,1:8,2:9} + typeDict = {0: 6, 1: 8, 2: 9} print(dir(self)) print('Object '+self.obj.Name) - if self.tess is not None : - print('Tessellated '+self.tess.Name) + if self.tess is not None: + print('Tessellated '+self.tess.Name) ty = typeDict[self.form.type.currentIndex()] ml = self.form.maxLen.value.text() cl = self.form.curveLen.value.text() pl = self.form.pointLen.value.text() print('type : '+str(ty)+' ml : '+ml+' cl : '+cl+' pl : '+pl) - if hasattr(self.obj,'Proxy') : - print('has proxy') - if hasattr(self.obj.Proxy,'SourceObj') : - print('Has source Object') - if meshObject(self.obj.Proxy.SourceObj,2,ty,\ - float(ml),float(cl),float(pl)) == True : - facets = getFacets() - vertex = getVertex() - self.processMesh(vertex,facets) - return - - if meshObject(self.obj,2,ty, \ - float(ml),float(cl),float(pl)) == True : - facets = getFacets() - vertex = getVertex() - if self.tess is None : - name ='GDMLTessellate_'+self.obj.Name - parent = None - if hasattr(self.obj,'InList') : - if len(self.obj.InList) > 0 : - parent = self.obj.InList[0] - self.tess = parent.newObject('Part::FeaturePython',name) - if parent is None : - self.tess = FreeCAD.ActiveDocument.addObject( \ - 'Part::FeaturePython',name) - GDMLGmshTessellated(self.tess,self.obj,getMeshLen(self.obj),vertex, facets, \ - "mm", getSelectedMaterial()) - else : - self.processMesh(vertex,facets) - + if hasattr(self.obj, 'Proxy'): + print('has proxy') + if hasattr(self.obj.Proxy, 'SourceObj'): + print('Has source Object') + if meshObject(self.obj.Proxy.SourceObj, 2, ty, + float(ml), float(cl), float(pl)) is True: + facets = getFacets() + vertex = getVertex() + self.processMesh(vertex, facets) + return + + if meshObject(self.obj, 2, ty, + float(ml), float(cl), float(pl)) is True: + facets = getFacets() + vertex = getVertex() + if self.tess is None: + name = 'GDMLTessellate_'+self.obj.Name + parent = None + if hasattr(self.obj, 'InList'): + if len(self.obj.InList) > 0: + parent = self.obj.InList[0] + self.tess = parent.newObject('Part::FeaturePython', name) + if parent is None: + self.tess = FreeCAD.ActiveDocument.addObject( + 'Part::FeaturePython', name) + GDMLGmshTessellated(self.tess, self.obj, + getMeshLen(self.obj), vertex, facets, + "mm", getSelectedMaterial()) + else: + self.processMesh(vertex, facets) + print('Check Form') - #print(dir(self.form)) - if not hasattr(self.form,'infoGroup') : - self.form.infoGroup = QtGui.QGroupBox('Mesh Information') - print('Mesh Info Layout') - layMeshInfo=QtGui.QHBoxLayout() - layMeshInfo.addWidget(self.form.Vertex) - layMeshInfo.addWidget(self.form.Facets) - #layMeshInfo.addWidget(self.form.Nodes) - self.form.infoGroup.setLayout(layMeshInfo) - self.form.Vlayout.addWidget(self.form.infoGroup) - #self.form.setLayout(self.form.Vlayout) - self.processMesh(vertex,facets) - - def leaveEvent(self, event) : + # print(dir(self.form)) + if not hasattr(self.form, 'infoGroup'): + self.form.infoGroup = QtGui.QGroupBox('Mesh Information') + print('Mesh Info Layout') + layMeshInfo = QtGui.QHBoxLayout() + layMeshInfo.addWidget(self.form.Vertex) + layMeshInfo.addWidget(self.form.Facets) + # layMeshInfo.addWidget(self.form.Nodes) + self.form.infoGroup.setLayout(layMeshInfo) + self.form.Vlayout.addWidget(self.form.infoGroup) + # self.form.setLayout(self.form.Vlayout) + self.processMesh(vertex, facets) + + def leaveEvent(self, event): print('Leave Event II') - def focusOutEvent(self, event) : + def focusOutEvent(self, event): print('Out of Focus II') -class TessellateFeature : - - def Activated(self) : - import Mesh + +class TessellateFeature: + + def Activated(self): import MeshPart from .GDMLObjects import GDMLTessellated, GDMLTriangular, \ ViewProvider, ViewProviderExtension for obj in FreeCADGui.Selection.getSelection(): - #if len(obj.InList) == 0: # allowed only for for top level objects + # if len(obj.InList) == 0: # allowed only for for top level objects print('Action Tessellate') - if hasattr(obj,'Shape') : - shape = obj.Shape.copy(False) - try : # Only supported if smesh built with netgen - mesh = MeshPart.meshFromShape(Shape=shape,Fineness=2,\ - SecondOrder=0,Optimize=1,AllowQuad=0) - except : - mesh = MeshPart.meshFromShape(Shape=shape,MaxArea=shape.Area) - print('Points : '+str(mesh.CountPoints)) - #print(mesh.Points) - print('Facets : '+str(mesh.CountFacets)) - #print(mesh.Facets) - name ='GDMLTessellate_'+obj.Label - vol = createPartVol(obj) - print(obj.Label) - print(obj.Placement) - if hasattr(obj,'material') : - mat = obj.material - else : - mat = getSelectedMaterial() - myTess = vol.newObject('Part::FeaturePython',name) - #GDMLTessellated(myTess,mesh.Topology[0],mesh.Topology[1], \ - GDMLTessellated(myTess,mesh.Topology[0],mesh.Facets,True, \ - "mm", mat) - # Update Part Placment with source Placement - vol.Placement = obj.Placement - base = obj.Placement.Base - print(type(base)) - myTess.Placement.Base = base.multiply(-1.0) - FreeCAD.ActiveDocument.recompute() - if FreeCAD.GuiUp : - ViewProvider(myTess.ViewObject) - obj.ViewObject.Visibility = False - myTess.ViewObject.DisplayMode = 'Flat Lines' - FreeCADGui.SendMsgToActiveView("ViewFit") - + if hasattr(obj, 'Shape'): + shape = obj.Shape.copy(False) + mesh = MeshPart.meshFromShape(Shape=shape, Fineness=2, + SecondOrder=0, Optimize=1, + AllowQuad=0) + print('Points : '+str(mesh.CountPoints)) + # print(mesh.Points) + print('Facets : '+str(mesh.CountFacets)) + # print(mesh.Facets) + name = 'GDMLTessellate_'+obj.Label + vol = createPartVol(obj) + print(obj.Label) + print(obj.Placement) + if hasattr(obj, 'material'): + mat = obj.material + else: + mat = getSelectedMaterial() + myTess = vol.newObject('Part::FeaturePython', name) + # GDMLTessellated(myTess,mesh.Topology[0],mesh.Topology[1], \ + GDMLTessellated(myTess, mesh.Topology[0], mesh.Facets, True, + "mm", mat) + # Update Part Placment with source Placement + vol.Placement = obj.Placement + base = obj.Placement.Base + print(type(base)) + myTess.Placement.Base = base.multiply(-1.0) + FreeCAD.ActiveDocument.recompute() + if FreeCAD.GuiUp: + ViewProvider(myTess.ViewObject) + obj.ViewObject.Visibility = False + myTess.ViewObject.DisplayMode = 'Flat Lines' + FreeCADGui.SendMsgToActiveView("ViewFit") + def GetResources(self): - return {'Pixmap' : 'GDML_Tessellate', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup',\ - 'GDML Tessellate Selected Object'), 'Tessellate_Planar': \ - QtCore.QT_TRANSLATE_NOOP('GDML_PolyGroup', \ - 'Tesselate Selected Planar Object')} - -class TessellateGmshFeature : - - def Activated(self) : - - import ObjectsFem + return {'Pixmap': 'GDML_Tessellate', + 'MenuText': QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', + 'GDML Tessellate Selected Object'), + 'Tessellate_Planar': QtCore.QT_TRANSLATE_NOOP('GDML_PolyGroup', + 'Tesselate Selected Planar Object')} + + +class TessellateGmshFeature: + + def Activated(self): + from .GmshUtils import initialize, meshObject, \ getVertex, getFacets, getMeshLen, printMeshInfo, printMyInfo @@ -1189,83 +1267,84 @@ def Activated(self) : print('Action Gmsh Activated') for obj in FreeCADGui.Selection.getSelection(): - #if len(obj.InList) == 0: # allowed only for for top level objects + # if len(obj.InList) == 0: # allowed only for for top level objects print('Action Gmsh Tessellate') - #print(dir(obj)) + # print(dir(obj)) print(obj.Name) - if hasattr(obj,'Shape') and obj.TypeId != 'App::Part' : - if FreeCADGui.Control.activeDialog() == False : - print('Build panel for TO BE Gmeshed') - panel = AddTessellateTask(obj) - if hasattr(obj,'Proxy') : - print(obj.Proxy.Type) - if obj.Proxy.Type == 'GDMLGmshTessellated' : - print('Build panel for EXISTING Gmsh Tessellate') - panel.form.meshInfoLayout=QtGui.QHBoxLayout() - panel.form.meshInfoLayout.addWidget(oField('Vertex',6, \ - str(len(obj.Proxy.Vertex)))) - panel.form.meshInfoLayout.addWidget(oField('Facets',6, \ - str(len(obj.Proxy.Facets)))) - panel.form.Vlayout.addLayout(panel.form.meshInfoLayout) - panel.form.setLayout(panel.form.Vlayout) - FreeCADGui.Control.showDialog(panel) - else : - print('Already an Active Task') + if hasattr(obj, 'Shape') and obj.TypeId != 'App::Part': + if FreeCADGui.Control.activeDialog() is False: + print('Build panel for TO BE Gmeshed') + panel = AddTessellateTask(obj) + if hasattr(obj, 'Proxy'): + print(obj.Proxy.Type) + if obj.Proxy.Type == 'GDMLGmshTessellated': + print('Build panel for EXISTING Gmsh Tessellate') + panel.form.meshInfoLayout = QtGui.QHBoxLayout() + panel.form.meshInfoLayout.addWidget(oField('Vertex', 6, + str(len(obj.Proxy.Vertex)))) + panel.form.meshInfoLayout.addWidget(oField('Facets', 6, + str(len(obj.Proxy.Facets)))) + panel.form.Vlayout.addLayout(panel.form.meshInfoLayout) + panel.form.setLayout(panel.form.Vlayout) + FreeCADGui.Control.showDialog(panel) + else: + print('Already an Active Task') return - def GetResources(self): - return {'Pixmap' : 'GDML_Tessellate_Gmsh', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup',\ - 'Gmsh & Tessellate'), 'Tessellate_Gmsh': \ - QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', \ - 'Mesh & Tessellate Selected Planar Object')} + return {'Pixmap': 'GDML_Tessellate_Gmsh', + 'MenuText': QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', + 'Gmsh & Tessellate'), + 'Tessellate_Gmsh': QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', + 'Mesh & Tessellate Selected Planar Object')} + + +class Mesh2TessFeature: + + def Activated(self): -class Mesh2TessFeature : - - def Activated(self) : - from .GDMLObjects import GDMLTessellated, GDMLTriangular, \ ViewProvider, ViewProviderExtension for obj in FreeCADGui.Selection.getSelection(): - #if len(obj.InList) == 0: # allowed only for for top level objects + # if len(obj.InList) == 0: # allowed only for for top level objects print(obj.TypeId) - if hasattr(obj,'Mesh') : - # Mesh Object difficult to determine parent - print('Action Mesh 2 Tessellate') - print('Points : '+str(obj.Mesh.CountPoints)) - print('Facets : '+str(obj.Mesh.CountFacets)) - #print(obj.Mesh.Topology[0]) - #print(obj.Mesh.Topology[1]) - vol = createPartVol(obj) - if hasattr(obj,'material') : - mat = obj.material - else : - mat = getSelectedMaterial() - m2t = vol.newObject('Part::FeaturePython',\ - "GDMLTessellate_Mesh2Tess") - GDMLTessellated(m2t,obj.Mesh.Topology[0],obj.Mesh.Facets,True, \ - "mm",mat) - if FreeCAD.GuiUp : - obj.ViewObject.Visibility = False - #print(dir(obj.ViewObject)) - ViewProvider(m2t.ViewObject) - - FreeCAD.ActiveDocument.recompute() - FreeCADGui.SendMsgToActiveView("ViewFit") - + if hasattr(obj, 'Mesh'): + # Mesh Object difficult to determine parent + print('Action Mesh 2 Tessellate') + print('Points : '+str(obj.Mesh.CountPoints)) + print('Facets : '+str(obj.Mesh.CountFacets)) + # print(obj.Mesh.Topology[0]) + # print(obj.Mesh.Topology[1]) + vol = createPartVol(obj) + if hasattr(obj, 'material'): + mat = obj.material + else: + mat = getSelectedMaterial() + m2t = vol.newObject('Part::FeaturePython', + "GDMLTessellate_Mesh2Tess") + GDMLTessellated(m2t, obj.Mesh.Topology[0], obj.Mesh.Facets, True, + "mm", mat) + if FreeCAD.GuiUp: + obj.ViewObject.Visibility = False + # print(dir(obj.ViewObject)) + ViewProvider(m2t.ViewObject) + + FreeCAD.ActiveDocument.recompute() + FreeCADGui.SendMsgToActiveView("ViewFit") + def GetResources(self): - return {'Pixmap' : 'GDML_Mesh2Tess', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup',\ - 'Mesh 2 Tess'), 'Mesh2Tess': \ - QtCore.QT_TRANSLATE_NOOP('GDML_TessyGroup', \ - 'Create GDML Tessellate from FC Mesh')} - -class Tess2MeshFeature : - - def Activated(self) : - + return {'Pixmap': 'GDML_Mesh2Tess', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', + 'Mesh 2 Tess'), 'Mesh2Tess': + QtCore.QT_TRANSLATE_NOOP('GDML_TessyGroup', + 'Create GDML Tessellate from FC Mesh')} + + +class Tess2MeshFeature: + + def Activated(self): + from .GDMLObjects import GDMLTessellated, GDMLTriangular, \ ViewProvider, ViewProviderExtension @@ -1274,52 +1353,39 @@ def Activated(self) : for obj in FreeCADGui.Selection.getSelection(): import MeshPart print('Action Tessellate 2 Mesh') - if hasattr(obj,'Proxy') : - if hasattr(obj.Proxy,'Type') : - if obj.Proxy.Type in ['GDMLTessellated', \ - 'GDMLGmshTessellated','GDMLTetrahedron'] : - parent = None - if hasattr(obj,'InList') : - if len(obj.InList) > 0 : - parent = obj.InList[0] - mshObj = parent.newObject('Mesh::Feature',obj.Name) - if parent is None : - mshObj = FreeCAD.ActiveDocument.addObject( \ - 'Mesh::Feature',obj.Name) - mshObj.Mesh = MeshPart.meshFromShape(obj.Shape) - - #if obj.Proxy.Type == 'GDMLTetrahedron' : - # print('Tetrahedron2Mesh') - # mesh = Tetrahedron2Mesh(obj) - - #if mesh is not None : - # print('Add Mesh') - # parent = None - # if hasattr(obj,'InList') : - # if len(obj.InList) > 0 : - # parent = obj.InList[0] - # mshObj = parent.newObject('Mesh::Feature',obj.Name) - # if parent is None : - # mshObj = FreeCAD.ActiveDocument.addObject( \ - # 'Mesh::Feature',obj.Name) - # mshObj.Mesh = mesh - if FreeCAD.GuiUp : - obj.ViewObject.Visibility = False - mshObj.ViewObject.DisplayMode = "Wireframe" - FreeCAD.ActiveDocument.recompute() - FreeCADGui.SendMsgToActiveView("ViewFit") + if hasattr(obj, 'Proxy'): + if hasattr(obj.Proxy, 'Type'): + if obj.Proxy.Type in ['GDMLTessellated', + 'GDMLGmshTessellated', + 'GDMLTetrahedron']: + parent = None + if hasattr(obj, 'InList'): + if len(obj.InList) > 0: + parent = obj.InList[0] + mshObj = parent.newObject('Mesh::Feature', obj.Name) + if parent is None: + mshObj = FreeCAD.ActiveDocument.addObject( + 'Mesh::Feature', obj.Name) + mshObj.Mesh = MeshPart.meshFromShape(obj.Shape) + if FreeCAD.GuiUp: + obj.ViewObject.Visibility = False + mshObj.ViewObject.DisplayMode = "Wireframe" + FreeCAD.ActiveDocument.recompute() + FreeCADGui.SendMsgToActiveView("ViewFit") + def GetResources(self): - return {'Pixmap' : 'GDML_Tess2Mesh', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup',\ - 'Tess2Mesh'), 'Tess 2 Mesh': \ - QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', \ - 'Create FC Mesh from GDML Tessellate')} - -class TetrahedronFeature : - - def Activated(self) : - + return {'Pixmap': 'GDML_Tess2Mesh', 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', + 'Tess2Mesh'), 'Tess 2 Mesh': + QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', + 'Create FC Mesh from GDML Tessellate')} + + +class TetrahedronFeature: + + def Activated(self): + from .GDMLObjects import GDMLTetrahedron, ViewProvider from .GmshUtils import initialize, meshObj, \ getTetrahedrons, printMeshInfo, printMyInfo @@ -1327,264 +1393,267 @@ def Activated(self) : for obj in FreeCADGui.Selection.getSelection(): print('Action Tetrahedron') initialize() - if meshObj(obj,3) == True : - tetraheds = getTetrahedrons() - if tetraheds is not None : - print('tetraheds : '+str(len(tetraheds))) - name ='GDMLTetrahedron_'+obj.Name - parent = None - if hasattr(obj,'InList') : - if len(obj.InList) > 0 : - parent = obj.InList[0] - myTet = parent.newObject('Part::FeaturePython',name) - if parent is None : - myTet = FreeCAD.ActiveDocument.addObject( \ - 'Part::FeaturePython',name) - GDMLTetrahedron(myTet,tetraheds,"mm",getSelectedMaterial()) - if FreeCAD.GuiUp : - obj.ViewObject.Visibility = False - ViewProvider(myTet.ViewObject) - myTet.ViewObject.DisplayMode = "Wireframe" - FreeCAD.ActiveDocument.recompute() - FreeCADGui.SendMsgToActiveView("ViewFit") - else : - FreeCAD.Console.PrintMessage('Not able to produce quandrants for this shape') + if meshObj(obj, 3) is True: + tetraheds = getTetrahedrons() + if tetraheds is not None: + print('tetraheds : '+str(len(tetraheds))) + name = 'GDMLTetrahedron_'+obj.Name + parent = None + if hasattr(obj, 'InList'): + if len(obj.InList) > 0: + parent = obj.InList[0] + myTet = parent.newObject('Part::FeaturePython', name) + if parent is None: + myTet = FreeCAD.ActiveDocument.addObject( + 'Part::FeaturePython', name) + GDMLTetrahedron(myTet, tetraheds, "mm", getSelectedMaterial()) + if FreeCAD.GuiUp: + obj.ViewObject.Visibility = False + ViewProvider(myTet.ViewObject) + myTet.ViewObject.DisplayMode = "Wireframe" + FreeCAD.ActiveDocument.recompute() + FreeCADGui.SendMsgToActiveView("ViewFit") + else: + FreeCAD.Console.PrintMessage('Not able to produce quandrants for this shape') def GetResources(self): - return {'Pixmap' : 'GDML_Tetrahedron', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup',\ - 'Tetrahedron'), 'Tetrehedron': \ - QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', \ - 'Create Tetrahedron from FC Shape')} - -class CycleFeature : - - def Activated(self) : - - def toggle(obj) : - #print ("Toggle "+obj.Label) - #print (obj.ViewObject.DisplayMode) - #print (obj.ViewObject.Visibility) - if obj.ViewObject.Visibility == False : - try : - obj.ViewObject.DisplayMode = 'Shaded' - except : - print(obj.Label+' No Shaded') - obj.ViewObject.Visibility = True - else : - if obj.ViewObject.DisplayMode == 'Shaded' : - obj.ViewObject.DisplayMode = 'Wireframe' - else : - obj.ViewObject.Visibility = False - - def cycle(obj) : - #print ("Toggle : "+ obj.Label) - #print (dir(obj)) - #print("TypeId : "+str(obj.TypeId)) - if obj.TypeId == "App::Part" : - for i in obj.OutList : - #print(i) - #print(dir(i)) - #print (i.TypeId) - if i.TypeId != "App::Origin" : - cycle(i) - elif obj.TypeId =="App::Origin" : + return {'Pixmap': 'GDML_Tetrahedron', + 'MenuText': QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', + 'Tetrahedron'), + 'Tetrehedron': QtCore.QT_TRANSLATE_NOOP('GDML_TessGroup', + 'Create Tetrahedron from FC Shape')} + + +class CycleFeature: + + def Activated(self): + + def toggle(obj): + # print ("Toggle "+obj.Label) + # print (obj.ViewObject.DisplayMode) + # print (obj.ViewObject.Visibility) + if obj.ViewObject.Visibility is False: + try: + obj.ViewObject.DisplayMode = 'Shaded' + except: + print(obj.Label+' No Shaded') + obj.ViewObject.Visibility = True + else: + if obj.ViewObject.DisplayMode == 'Shaded': + obj.ViewObject.DisplayMode = 'Wireframe' + else: + obj.ViewObject.Visibility = False + + def cycle(obj): + # print ("Toggle : "+ obj.Label) + # print (dir(obj)) + # print("TypeId : "+str(obj.TypeId)) + if obj.TypeId == "App::Part": + for i in obj.OutList: + # print(i) + # print(dir(i)) + # print (i.TypeId) + if i.TypeId != "App::Origin": + cycle(i) + elif obj.TypeId == "App::Origin": return - #print obj.isDerivedFrom('App::DocumentObjectGroupPython') + # print obj.isDerivedFrom('App::DocumentObjectGroupPython') # Is this a genuine group i.e. Volumes # Not Parts with Groups i.e. GDMLPolycone - elif obj.isDerivedFrom('App::DocumentObjectGroupPython') : - #print "Toggle Group" - for s in obj.Group : - #print s - cycle(s) + elif obj.isDerivedFrom('App::DocumentObjectGroupPython'): + # print "Toggle Group" + for s in obj.Group: + # print s + cycle(s) # Cycle through display options - elif hasattr(obj,'ViewObject') : - toggle(obj) + elif hasattr(obj, 'ViewObject'): + toggle(obj) - if hasattr(obj,'Base') and hasattr(obj,'Tool') : - print ("Boolean") - cycle(obj.Base) - cycle(obj.Tool) - + if hasattr(obj, 'Base') and hasattr(obj, 'Tool'): + print("Boolean") + cycle(obj.Base) + cycle(obj.Tool) for obj in FreeCADGui.Selection.getSelection(): - #if len(obj.InList) == 0: # allowed only for for top level objects + # if len(obj.InList) == 0: # allowed only for for top level objects cycle(obj) - def GetResources(self): - return {'Pixmap' : 'GDML_Cycle', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDML_CycleGroup',\ - 'Cycle Group'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDML_CycleGroup', \ - 'Cycle Object and all children display')} - -def expandFunction(obj, eNum) : + return {'Pixmap': 'GDML_Cycle', + 'MenuText': + QtCore.QT_TRANSLATE_NOOP('GDML_CycleGroup', + 'Cycle Group'), + 'ToolTip': + QtCore.QT_TRANSLATE_NOOP('GDML_CycleGroup', + 'Cycle Object and all children display')} + +def expandFunction(obj, eNum): from .importGDML import expandVolume print('Expand Function') # Get original volume name i.e. loose _ or _nnn name = obj.Label[13:] - if hasattr(obj,'VolRef') : - volRef = obj.VolRef - else : - volRef = name - if obj.TypeId != 'App::Link' : - expandVolume(obj,volRef,eNum,3) - obj.Label = name + if hasattr(obj, 'VolRef'): + volRef = obj.VolRef + else: + volRef = name + if obj.TypeId != 'App::Link': + expandVolume(obj, volRef, eNum, 3) + obj.Label = name -class ExpandFeature : +class ExpandFeature: - def Activated(self) : - - print('Expand Feature') + def Activated(self): + + print('Expand Feature') for obj in FreeCADGui.Selection.getSelection(): - #if len(obj.InList) == 0: # allowed only for for top level objects - # add check for Part i.e. Volume + # if len(obj.InList) == 0: # allowed only for for top level objects + # add check for Part i.e. Volume print("Selected") print(obj.Label[:13]) - if obj.Label[:13] == "NOT_Expanded_" : - expandFunction(obj,0) - if obj.Label[:5] == "Link_" : - if hasattr(obj,'LinkedObject') : - if obj.LinkedObject.Label[0:13] == 'NOT_Expanded_' : - expandFunction(obj.LinkedObject,0) + if obj.Label[:13] == "NOT_Expanded_": + expandFunction(obj, 0) + if obj.Label[:5] == "Link_": + if hasattr(obj, 'LinkedObject'): + if obj.LinkedObject.Label[0:13] == 'NOT_Expanded_': + expandFunction(obj.LinkedObject, 0) def GetResources(self): - return {'Pixmap' : 'GDML_Expand_One', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDML_Expand_One',\ - 'Expand Volume'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDML_Expand_One', \ - 'Expand Volume')} + return {'Pixmap': 'GDML_Expand_One', + 'MenuText': QtCore.QT_TRANSLATE_NOOP('GDML_Expand_One', + 'Expand Volume'), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP('GDML_Expand_One', + 'Expand Volume')} + + +class ExpandMaxFeature: -class ExpandMaxFeature : + def Activated(self): - def Activated(self) : - for obj in FreeCADGui.Selection.getSelection(): - #if len(obj.InList) == 0: # allowed only for for top level objects - # add check for Part i.e. Volume + # if len(obj.InList) == 0: # allowed only for for top level objects + # add check for Part i.e. Volume print("Selected") print(obj.Label[:13]) - if obj.Label[:13] == "NOT_Expanded_" : - expandFunction(obj,-1) - if obj.Label[:5] == "Link_" : - if hasattr(obj,'LinkedObject') : - if obj.LinkedObject.Label[0:13] == 'NOT_Expanded_' : - expandFunction(obj.LinkedObject,-1) + if obj.Label[:13] == "NOT_Expanded_": + expandFunction(obj, -1) + if obj.Label[:5] == "Link_": + if hasattr(obj, 'LinkedObject'): + if obj.LinkedObject.Label[0:13] == 'NOT_Expanded_': + expandFunction(obj.LinkedObject, -1) def GetResources(self): - return {'Pixmap' : 'GDML_Expand_Max', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDML_Expand_Max',\ - 'Max Expand Volume'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDML_Expand_Max', \ - 'Max Expand Volume')} + return {'Pixmap': 'GDML_Expand_Max', + 'MenuText': QtCore.QT_TRANSLATE_NOOP('GDML_Expand_Max', + 'Max Expand Volume'), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP('GDML_Expand_Max', + 'Max Expand Volume')} -class CompoundFeature : - - def Activated(self) : + +class CompoundFeature: + + def Activated(self): from .GDMLObjects import GDMLcommon import ObjectsFem - - def allocateMaterial(doc, analObj, materials, material) : - print("Allocate Material : ",material) - for n in materials.OutList : - if n.Label == material : - print("Found Material") - matObj = ObjectsFem.makeMaterialSolid(doc, material) - mat = matObj.Material - mat['Name'] = material - mat['Density'] = str(n.density) + " kg/m^3" - mat['ThermalConductivity'] = str(n.conduct) + " W/m/K" - mat['ThermalExpansionCoefficient'] = str(n.expand) + " m/m/K" - mat['SpecificHeat'] = str(n.specific) + " J/kg/K" - #print(mat) - #print(mat['Density']) - matObj.Material = mat - analObj.addObject(matObj) - - def addToList(objList, matList, obj) : - print(obj.Name) - if hasattr(obj,'Proxy') : - #print("Has proxy") - #material_object = ObjectsFem.makeMaterialSolid \ - # (doc,obj.Name+"-Material") - #allocateMaterial(material_object, obj.Material) - if isinstance(obj.Proxy,GDMLcommon) : - objList.append(obj) - if obj.material not in matList : - matList.append(obj.material) - - if obj.TypeId == 'App::Part' and hasattr(obj,'OutList') : - #if hasattr(obj,'OutList') : - #print("Has OutList + len "+str(len(obj.OutList))) - for i in obj.OutList : - #print('Call add to List '+i.Name) - addToList(objList, matList, i) - - def myaddCompound(obj,count) : + + def allocateMaterial(doc, analObj, materials, material): + print("Allocate Material : ", material) + for n in materials.OutList: + if n.Label == material: + print("Found Material") + matObj = ObjectsFem.makeMaterialSolid(doc, material) + mat = matObj.Material + mat['Name'] = material + mat['Density'] = str(n.density) + " kg/m^3" + mat['ThermalConductivity'] = str(n.conduct) + " W/m/K" + mat['ThermalExpansionCoefficient'] = str(n.expand) + " m/m/K" + mat['SpecificHeat'] = str(n.specific) + " J/kg/K" + # print(mat) + # print(mat['Density']) + matObj.Material = mat + analObj.addObject(matObj) + + def addToList(objList, matList, obj): + print(obj.Name) + if hasattr(obj, 'Proxy'): + # print("Has proxy") + # material_object = ObjectsFem.makeMaterialSolid \ + # (doc,obj.Name+"-Material") + # allocateMaterial(material_object, obj.Material) + if isinstance(obj.Proxy, GDMLcommon): + objList.append(obj) + if obj.material not in matList: + matList.append(obj.material) + + if obj.TypeId == 'App::Part' and hasattr(obj, 'OutList'): + # if hasattr(obj,'OutList') : + # print("Has OutList + len "+str(len(obj.OutList))) + for i in obj.OutList: + # print('Call add to List '+i.Name) + addToList(objList, matList, i) + + def myaddCompound(obj, count): # count == 0 World Volume - print ("Add Compound "+obj.Label) + print("Add Compound "+obj.Label) volList = [] matList = [] addToList(volList, matList, obj) - if count == 0 : - del volList[0] - del matList[0] + if count == 0: + del volList[0] + del matList[0] # DO not delete World Material as it may be repeat - print('vol List') + print('vol List') print(volList) print('Material List') - #print(matList) + # print(matList) doc = FreeCAD.activeDocument() - analysis_object = ObjectsFem.makeAnalysis(doc,"Analysis") + analysis_object = ObjectsFem.makeAnalysis(doc, "Analysis") materials = FreeCAD.ActiveDocument.Materials - for m in matList : + for m in matList: allocateMaterial(doc, analysis_object, materials, m) - comp = obj.newObject("Part::Compound","Compound") + comp = obj.newObject("Part::Compound", "Compound") comp.Links = volList FreeCAD.ActiveDocument.recompute() - objs = FreeCADGui.Selection.getSelection() - #if len(obj.InList) == 0: # allowed only for for top level objects + # if len(obj.InList) == 0: # allowed only for for top level objects print(len(objs)) - if len(objs) > 0 : - obj = objs[0] - if obj.TypeId == 'App::Part' : - myaddCompound(obj,len(obj.InList)) + if len(objs) > 0: + obj = objs[0] + if obj.TypeId == 'App::Part': + myaddCompound(obj, len(obj.InList)) def GetResources(self): - return {'Pixmap' : 'GDML_Compound', 'MenuText': \ - QtCore.QT_TRANSLATE_NOOP('GDML_Compound',\ - 'Add compound to Volume'), 'ToolTip': \ - QtCore.QT_TRANSLATE_NOOP('GDML_Compound', \ - 'Add a Compound of Volume')} - -FreeCADGui.addCommand('CycleCommand',CycleFeature()) -FreeCADGui.addCommand('ExpandCommand',ExpandFeature()) -FreeCADGui.addCommand('ExpandMaxCommand',ExpandMaxFeature()) -FreeCADGui.addCommand('ColourMapCommand',ColourMapFeature()) -FreeCADGui.addCommand('SetMaterialCommand',SetMaterialFeature()) -FreeCADGui.addCommand('BooleanCutCommand',BooleanCutFeature()) -FreeCADGui.addCommand('BooleanIntersectionCommand',BooleanIntersectionFeature()) -FreeCADGui.addCommand('BooleanUnionCommand',BooleanUnionFeature()) -FreeCADGui.addCommand('BoxCommand',BoxFeature()) -FreeCADGui.addCommand('EllipsoidCommand',EllispoidFeature()) -FreeCADGui.addCommand('ElTubeCommand',ElliTubeFeature()) -FreeCADGui.addCommand('ConeCommand',ConeFeature()) -FreeCADGui.addCommand('SphereCommand',SphereFeature()) -FreeCADGui.addCommand('TorusCommand',TorusFeature()) -FreeCADGui.addCommand('TrapCommand',TrapFeature()) -FreeCADGui.addCommand('TubeCommand',TubeFeature()) -FreeCADGui.addCommand('PolyHedraCommand',PolyHedraFeature()) -FreeCADGui.addCommand('AddCompound',CompoundFeature()) -FreeCADGui.addCommand('TessellateCommand',TessellateFeature()) -FreeCADGui.addCommand('TessellateGmshCommand',TessellateGmshFeature()) -FreeCADGui.addCommand('DecimateCommand',DecimateFeature()) -FreeCADGui.addCommand('Mesh2TessCommand',Mesh2TessFeature()) -FreeCADGui.addCommand('Tess2MeshCommand',Tess2MeshFeature()) -FreeCADGui.addCommand('TetrahedronCommand',TetrahedronFeature()) + return {'Pixmap': 'GDML_Compound', + 'MenuText': QtCore.QT_TRANSLATE_NOOP('GDML_Compound', + 'Add compound to Volume'), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP('GDML_Compound', + 'Add a Compound of Volume')} + + +FreeCADGui.addCommand('CycleCommand', CycleFeature()) +FreeCADGui.addCommand('ExpandCommand', ExpandFeature()) +FreeCADGui.addCommand('ExpandMaxCommand', ExpandMaxFeature()) +FreeCADGui.addCommand('ColourMapCommand', ColourMapFeature()) +FreeCADGui.addCommand('SetMaterialCommand', SetMaterialFeature()) +FreeCADGui.addCommand('BooleanCutCommand', BooleanCutFeature()) +FreeCADGui.addCommand('BooleanIntersectionCommand', BooleanIntersectionFeature()) +FreeCADGui.addCommand('BooleanUnionCommand', BooleanUnionFeature()) +FreeCADGui.addCommand('BoxCommand', BoxFeature()) +FreeCADGui.addCommand('EllipsoidCommand', EllispoidFeature()) +FreeCADGui.addCommand('ElTubeCommand', ElliTubeFeature()) +FreeCADGui.addCommand('ConeCommand', ConeFeature()) +FreeCADGui.addCommand('SphereCommand', SphereFeature()) +FreeCADGui.addCommand('TorusCommand', TorusFeature()) +FreeCADGui.addCommand('TrapCommand', TrapFeature()) +FreeCADGui.addCommand('TubeCommand', TubeFeature()) +FreeCADGui.addCommand('PolyHedraCommand', PolyHedraFeature()) +FreeCADGui.addCommand('AddCompound', CompoundFeature()) +FreeCADGui.addCommand('TessellateCommand', TessellateFeature()) +FreeCADGui.addCommand('TessellateGmshCommand', TessellateGmshFeature()) +FreeCADGui.addCommand('DecimateCommand', DecimateFeature()) +FreeCADGui.addCommand('Mesh2TessCommand', Mesh2TessFeature()) +FreeCADGui.addCommand('Tess2MeshCommand', Tess2MeshFeature()) +FreeCADGui.addCommand('TetrahedronCommand', TetrahedronFeature()) diff --git a/freecad/gdml/GDMLMaterials.py b/freecad/gdml/GDMLMaterials.py index 872fe4c7c..da08cc61f 100644 --- a/freecad/gdml/GDMLMaterials.py +++ b/freecad/gdml/GDMLMaterials.py @@ -1,28 +1,29 @@ -#************************************************************************** -#* * -#* Copyright (c) 2021 Keith Sloan * -#* (c) Munther Hindi * -#* (c) Dam Lambert * -#* * -#* 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 * -#* * -#* Acknowledgements : * -#************************************************************************** -__title__="FreeCAD GDML Workbench - GUI Commands" +# Sun Jan 30 11:32:46 AM PST 2022 +# ************************************************************************** +# * * +# * Copyright (c) 2021 Keith Sloan * +# * (c) Munther Hindi * +# * (c) Dam Lambert * +# * * +# * 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 * +# * * +# * Acknowledgements : * +# ************************************************************************** +__title__ = "FreeCAD GDML Workbench - GUI Commands" __author__ = "Keith Sloan" __url__ = ["http://www.freecadweb.org"] @@ -30,51 +31,93 @@ from PySide import QtGui, QtCore + class GDMLMaterial(QtGui.QComboBox): - def __init__(self,matList,mat) : - super().__init__() - self.addItems(matList) - self.setEditable(False) - if mat is not None : - self.setCurrentIndex(matList.index(mat)) + def __init__(self, matList, mat): + super().__init__() + self.addItems(matList) + self.setEditable(False) + if mat is not None: + self.setCurrentIndex(matList.index(mat)) + + def getItem(self): + return str(self.currentText()) - def getItem(self): - return str(self.currentText()) -def getMaterialsList() : +def getMaterialsList(): matList = [] doc = FreeCAD.activeDocument() - try : - materials = doc.Materials - geant4 = doc.Geant4 - g4Mats = doc.getObject('G4Materials') - - except : - from .importGDML import processGEANT4 - from .init_gui import joinDir - - print('Load Geant4 Materials XML') - processGEANT4(doc,joinDir("Resources/Geant4Materials.xml")) - materials = doc.Materials - geant4 = doc.Geant4 - g4Mats = doc.getObject('G4Materials') - try : - if materials is not None : - for m in materials.OutList : - if m.Label != "Geant4" : - matList.append(m.Label) - #print(matList) - - except : - pass - - try : - if g4Mats is not None : - for m in g4Mats.OutList : - matList.append(m.Label) - #print(matList) - except : - pass + try: + materials = doc.Materials + geant4 = doc.Geant4 + g4Mats = doc.getObject('G4Materials') + + except: + from .importGDML import processGEANT4 + from .init_gui import joinDir + + print('Load Geant4 Materials XML') + processGEANT4(doc, joinDir("Resources/Geant4Materials.xml")) + materials = doc.Materials + geant4 = doc.Geant4 + g4Mats = doc.getObject('G4Materials') + + try: + if materials is not None: + for m in materials.OutList: + if m.Label != "Geant4": + matList.append(m.Label) + # print(matList) + except: + pass + + try: + if g4Mats is not None: + for m in g4Mats.OutList: + matList.append(m.Label) + # print(matList) + except: + pass return matList + + +def getGroupedMaterials(): + print('getGroupedMaterials') + from .GDMLObjects import GroupedMaterials + from .importGDML import setupEtree + from .init_gui import joinDir + + if len(GroupedMaterials) == 0: + etree, root = setupEtree(joinDir("Resources/Geant4Materials.xml")) + materials = root.find('materials') + + for material in materials.findall('material'): + name = material.get('name') + print(name) + if name is None: + print("Missing Name") + else: + for auxiliary in material.findall('auxiliary'): + auxtype = auxiliary.get('auxtype') + if auxtype == 'Material-type': + auxvalue = auxiliary.get('auxvalue') + if auxvalue in GroupedMaterials: + GroupedMaterials[auxvalue].append(name) + else: + GroupedMaterials[auxvalue] = [name] + + doc = FreeCAD.activeDocument() + docMaterials = doc.Materials + matList = [] + if docMaterials is not None: + for m in docMaterials.OutList: + if m.Label != "Geant4": + if m.Label not in matList: + matList.append(m.Label) + + if len(matList) > 0: + GroupedMaterials['Normal'] = matList + + return GroupedMaterials diff --git a/freecad/gdml/GDMLObjects.py b/freecad/gdml/GDMLObjects.py index 85d77b481..0738ad8ba 100644 --- a/freecad/gdml/GDMLObjects.py +++ b/freecad/gdml/GDMLObjects.py @@ -1,32 +1,33 @@ # -*- coding: utf-8 -*- -# Mon Dec 6 10:02:57 AM PST 2021 +# insert date with Ctrl-u ESC-! date +# Wed Jan 26 04:44:48 PM PST 2022 # -#************************************************************************** -#* * -#* Copyright (c) 2017 Keith Sloan * -#* (c) Dam Lambert 2020 * -#* (c) Munther Hindi 2021 * -#* * -#* 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 * -#* * -#* Acknowledgements : * -#* * -#* * -#************************************************************************** +# ************************************************************************** +# * * +# * Copyright (c) 2017 Keith Sloan * +# * (c) Dam Lambert 2020 * +# * (c) Munther Hindi 2021 * +# * * +# * 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 * +# * * +# * Acknowledgements : * +# * * +# * * +# ************************************************************************** import FreeCAD, FreeCADGui, Part from pivy import coin @@ -39,230 +40,252 @@ # So need to be able to rebuild from Objects global MaterialsList MaterialsList = [] +global GroupedMaterials +GroupedMaterials = {} # dictionary of material lists by type global LengthQuantityList -LengthQuantityList = ['nm','um', 'mm','cm', 'dm','m', 'km'] +LengthQuantityList = ['nm', 'um', 'mm', 'cm', 'dm', 'm', 'km'] # cf definition https://wiki.freecadweb.org/Quantity -def setLengthQuantity(obj, m) : - if LengthQuantityList is not None : +def setLengthQuantity(obj, m): + if LengthQuantityList is not None: obj.lunit = LengthQuantityList obj.lunit = 0 - if len(LengthQuantityList) > 0 : - if not ( m == 0 or m is None ) : + if len(LengthQuantityList) > 0: + if not (m == 0 or m is None): obj.lunit = LengthQuantityList.index(m) - else : + else: obj.lunit = 2 -def addMaterialsFromGroup(doc, MatList, grpName) : + +def addMaterialsFromGroup(doc, MatList, grpName): mmats = doc.getObject(grpName) - if mmats is not None : - if hasattr(mmats,'Group') : - for i in mmats.Group : - MatList.append(i.Name) + if mmats is not None: + if hasattr(mmats, 'Group'): + for i in mmats.Group: + MatList.append(i.Name) -def rebuildMaterialsList() : + +def rebuildMaterialsList(): global MaterialsList print('Restore MaterialsList from Materials Lists') doc = FreeCAD.ActiveDocument - addMaterialsFromGroup(doc,MaterialsList,"Materials") - addMaterialsFromGroup(doc,MaterialsList,"G4Materials") - #print('MaterialsList') - #print(MaterialsList) + addMaterialsFromGroup(doc, MaterialsList, "Materials") + addMaterialsFromGroup(doc, MaterialsList, "G4Materials") + # print('MaterialsList') + # print(MaterialsList) + -def checkMaterial(material) : +def checkMaterial(material): global MaterialsList - try : - i = MaterialsList.index(material) + try: + i = MaterialsList.index(material) except ValueError: - return False + return False return True -def setMaterial(obj, m) : - #print('setMaterial') - if MaterialsList is not None : - if len(MaterialsList) > 0 : - obj.material = MaterialsList - obj.material = 0 - if not ( m == 0 or m is None ) : - try : - obj.material = MaterialsList.index(m) - except : - print('Not in List') - print(MaterialsList) - obj.material = 0 - return - return + +def setMaterial(obj, m): + # print('setMaterial') + if MaterialsList is not None: + if len(MaterialsList) > 0: + obj.material = MaterialsList + obj.material = 0 + if not (m == 0 or m is None): + try: + obj.material = MaterialsList.index(m) + except: + print('Not in List') + print(MaterialsList) + obj.material = 0 + return + return rebuildMaterialsList() setMaterial(obj, m) -def checkFullCircle(aunit, angle) : - #print(angle) - if aunit == 'deg' and angle == 360 : - return True - if aunit == 'rad' and angle == 2 * math.pi : - return True + +def checkFullCircle(aunit, angle): + # print(angle) + if aunit == 'deg' and angle == 360: + return True + if aunit == 'rad' and angle == 2 * math.pi: + return True return False + # Get angle in Radians -def getAngleRad(aunit,angle) : - #print("aunit : "+str(aunit)) - if aunit == 'deg' : # 0 radians 1 Degrees - return(angle*math.pi/180) - else : - return angle +def getAngleRad(aunit, angle): + # print("aunit : "+str(aunit)) + if aunit == 'deg': # 0 radians 1 Degrees + return(angle*math.pi/180) + else: + return angle + # Get angle in Degrees -def getAngleDeg(aunit,angle) : - #print("aunit : "+str(aunit)) - if aunit == 'rad' : # 0 radians 1 Degrees - return(angle*180/math.pi) - else : - return angle - -def makeRegularPolygon(n,r,z): +def getAngleDeg(aunit, angle): + # print("aunit : "+str(aunit)) + if aunit == 'rad': # 0 radians 1 Degrees + return(angle*180/math.pi) + else: + return angle + + +def makeRegularPolygon(n, r, z): from math import cos, sin, pi - vecs = [FreeCAD.Vector(cos(2*pi*i/n)*r, sin(2*pi*i/n)*r, z) \ + vecs = [FreeCAD.Vector(cos(2*pi*i/n)*r, sin(2*pi*i/n)*r, z) for i in range(n+1)] return vecs -def printPolyVec(n,v) : - print("Polygon : "+n) - for i in v : + +def printPolyVec(n, v): + print("Polygon : " + n) + for i in v: print("Vertex - x : "+str(i[0])+" y : "+str(i[1])+" z : "+str(i[2])) -def translate(shape,base) : + +def translate(shape, base): # Input Object and displacement vector - return a transformed shape - #return shape + # return shape myPlacement = FreeCAD.Placement() myPlacement.move(base) mat1 = myPlacement.toMatrix() - #print(mat1) + # print(mat1) mat2 = shape.Matrix - mat = mat1.multiply(mat2) - #print(mat) + mat = mat1.multiply(mat2) + # print(mat) retShape = shape.copy() retShape.transformShape(mat, True) return retShape -def make_face3(v1,v2,v3): + +def make_face3(v1, v2, v3): # helper method to create the faces - wire = Part.makePolygon([v1,v2,v3,v1]) + wire = Part.makePolygon([v1, v2, v3, v1]) face = Part.Face(wire) return face -def make_face4(v1,v2,v3,v4): + +def make_face4(v1, v2, v3, v4): # helper method to create the faces - wire = Part.makePolygon([v1,v2,v3,v4,v1]) + wire = Part.makePolygon([v1, v2, v3, v4, v1]) face = Part.Face(wire) return face -def makeFrustrum(num,poly0,poly1) : + +def makeFrustrum(num, poly0, poly1): # return list of faces - #print("Make Frustrum : "+str(num)+" Faces") + # print("Make Frustrum : "+str(num)+" Faces") faces = [] - for i in range(num) : - j = i + 1 - #print([poly0[i],poly0[j],poly1[j],poly1[i]]) - w = Part.makePolygon([poly0[i],poly0[j],poly1[j],poly1[i],poly0[i]]) - faces.append(Part.Face(w)) - #print("Number of Faces : "+str(len(faces))) + for i in range(num): + j = i + 1 + # print([poly0[i],poly0[j],poly1[j],poly1[i]]) + w = Part.makePolygon([poly0[i], poly0[j], poly1[j], + poly1[i], poly0[i]]) + faces.append(Part.Face(w)) + # print("Number of Faces : "+str(len(faces))) return(faces) -def angleSectionSolid(fp, rmax, z, shape) : + +def angleSectionSolid(fp, rmax, z, shape): # Different Solids have different rmax and height - #print("angleSectionSolid") - #print('rmax : '+str(rmax)) - #print('z : '+str(z)) - #print("aunit : "+fp.aunit) - startPhiDeg = getAngleDeg(fp.aunit,fp.startphi) - deltaPhiDeg = getAngleDeg(fp.aunit,fp.deltaphi) - #print('delta') - #print(deltaPhiDeg) - #print('start') - #print(startPhiDeg) - v1 = FreeCAD.Vector(0,0,0) - v2 = FreeCAD.Vector(rmax,0,0) - v3 = FreeCAD.Vector(rmax,0,z) - v4 = FreeCAD.Vector(0,0,z) - - f1 = make_face4(v1,v2,v3,v4) - s1 = f1.revolve(v1,v4,360-deltaPhiDeg) + # print("angleSectionSolid") + # print('rmax : '+str(rmax)) + # print('z : '+str(z)) + # print("aunit : "+fp.aunit) + startPhiDeg = getAngleDeg(fp.aunit, fp.startphi) + deltaPhiDeg = getAngleDeg(fp.aunit, fp.deltaphi) + # print('delta') + # print(deltaPhiDeg) + # print('start') + # print(startPhiDeg) + v1 = FreeCAD.Vector(0, 0, 0) + v2 = FreeCAD.Vector(rmax, 0, 0) + v3 = FreeCAD.Vector(rmax, 0, z) + v4 = FreeCAD.Vector(0, 0, z) + + f1 = make_face4(v1, v2, v3, v4) + s1 = f1.revolve(v1, v4, 360-deltaPhiDeg) # Problem with FreeCAD 0.18 - #s2 = s1.rotate(v1,v4,startPhiDeg) - - s2 = s1.rotate(v1,v4,deltaPhiDeg) - - #Part.show(s2) - #return(shape.cut(s2)) - #return(s2) - + # s2 = s1.rotate(v1,v4,startPhiDeg) + + s2 = s1.rotate(v1, v4, deltaPhiDeg) + + # Part.show(s2) + # return(shape.cut(s2)) + # return(s2) + shape = shape.cut(s2) - if startPhiDeg != 0 : - shape.rotate(FreeCAD.Vector(0,0,0), \ - FreeCAD.Vector(0,0,1),startPhiDeg) + if startPhiDeg != 0: + shape.rotate(FreeCAD.Vector(0, 0, 0), + FreeCAD.Vector(0, 0, 1), startPhiDeg) return shape -def indiceToRay(indiceIn): # Thanks to Dam - if indiceIn<1: + +def indiceToRay(indiceIn): # Thanks to Dam + if indiceIn < 1: return 0 else: - lray=[0.0, 1.0] - puissanceDown=2 + lray = [0.0, 1.0] + puissanceDown = 2 while len(lray) <= indiceIn: - for indiceTmp in range(1,puissanceDown,2): + for indiceTmp in range(1, puissanceDown, 2): lray.append(float(indiceTmp)/float(puissanceDown)) puissanceDown = 2 * puissanceDown return lray[indiceIn] - -def colorFromRay(rayIn): # Thanks to Dam - coeffR=coeffG=coeffB=1.0 - - if(rayIn<0.2 and rayIn>=0.0): - coeffR=1.0 - coeffG=rayIn*5.0 - coeffB=0.0 - elif(rayIn<0.4): - coeffR=2.0-(5.0*rayIn) - coeffG=1.0 - coeffB=0.0 - elif(rayIn<0.6): - coeffR=0.0 - coeffG=1.0 - coeffB=rayIn*5.0-2.0 - elif(rayIn<0.8): - coeffR=1.0 - coeffG=4.0-(5.0*rayIn) - coeffB=1.0 - elif(rayIn<=1.0): - coeffR=(5.0*rayIn)-4.0 - coeffG=0.0 - coeffB=1.0 - return (coeffR,coeffG,coeffB,0.0) + + +def colorFromRay(rayIn): # Thanks to Dam + coeffR = coeffG = coeffB = 1.0 + + if(rayIn < 0.2 and rayIn >= 0.0): + coeffR = 1.0 + coeffG = rayIn*5.0 + coeffB = 0.0 + elif(rayIn < 0.4): + coeffR = 2.0-(5.0*rayIn) + coeffG = 1.0 + coeffB = 0.0 + elif(rayIn < 0.6): + coeffR = 0.0 + coeffG = 1.0 + coeffB = rayIn*5.0-2.0 + elif(rayIn < 0.8): + coeffR = 1.0 + coeffG = 4.0-(5.0*rayIn) + coeffB = 1.0 + elif(rayIn <= 1.0): + coeffR = (5.0*rayIn)-4.0 + coeffG = 0.0 + coeffB = 1.0 + return (coeffR, coeffG, coeffB, 0.0) + def colourMaterial(m): - if MaterialsList is None : - return (0.5,0.5,0.5,0.0) - else : - if ( m is None ) : - return (0.5,0.5,0.5,0,0) - elif(len(MaterialsList)<=1): - return (0.5,0.5,0.5,0.0) - elif m not in MaterialsList : - return (0.5,0.5,0.5,0.0) - else: - coeffRGB = MaterialsList.index(m) - return colorFromRay(indiceToRay(coeffRGB)) - -def updateColour(obj, colour, material) : - if colour is None : - colour = colourMaterial(material) + if MaterialsList is None: + return (0.5, 0.5, 0.5, 0.0) + else: + if (m is None): + return (0.5, 0.5, 0.5, 0, 0) + elif(len(MaterialsList) <= 1): + return (0.5, 0.5, 0.5, 0.0) + elif m not in MaterialsList: + return (0.5, 0.5, 0.5, 0.0) + else: + coeffRGB = MaterialsList.index(m) + return colorFromRay(indiceToRay(coeffRGB)) + + +def updateColour(obj, colour, material): + if colour is None: + colour = colourMaterial(material) obj.ViewObject.ShapeColor = colour - #print(f'Colour {colour}') - if colour is not None : - obj.ViewObject.Transparency = int(colour[3]*100) + # print(f'Colour {colour}') + if colour is not None: + obj.ViewObject.Transparency = int(colour[3]*100) + def rotateAroundZ(nstep, z, r): ####################################### @@ -272,157 +295,188 @@ def rotateAroundZ(nstep, z, r): # z - list of z coordinates of polylines # r - list of r coordinates of polylines # - faces = [] verts = [] verts.append(FreeCAD.Vector(0, 0, z[0])) - verts.extend([FreeCAD.Vector(r[i], 0, z[i]) for i in range(0,len(z))]) - verts.append(FreeCAD.Vector(0, 0, z[len(z)-1]) ) + verts.extend([FreeCAD.Vector(r[i], 0, z[i]) for i in range(0, len(z))]) + verts.append(FreeCAD.Vector(0, 0, z[len(z)-1])) line = Part.makePolygon(verts) - surf = line.revolve(FreeCAD.Vector(0,0,0), FreeCAD.Vector(0,0,1), 360) + surf = line.revolve(FreeCAD.Vector(0, 0, 0), FreeCAD.Vector(0, 0, 1), 360) return Part.makeSolid(surf) - -class GDMLColourMapEntry : - def __init__(self,obj,colour,material) : - obj.addProperty("App::PropertyColor","colour", \ - "GDMLColourMapEntry","colour").colour=colour - obj.addProperty("App::PropertyEnumeration","material", \ - "GDMLColourMapEntry","Material") - setMaterial(obj, material) - -def indexBoolean(list,ln) : - #print('Length : '+str(ln)) - if ln > 3 : - #print(range(ln-3)) - for r in range(ln-2,-1,-1) : - t = list[r].TypeId - #print(t) - if t == 'Part::Cut' or t == 'Part::Fuse' or t == 'Part::Common' : - return r - return -1 - -class GDMLsolid : - def __init__(self, obj): - '''Init''' - #print('>>>>>') - #if hasattr(obj,'Label') : - # print('Label : '+obj.Label) - #print('TypeId : '+obj.TypeId) - #print(dir(obj)) - #if hasattr(obj,'InList') : - # print('InList') - # print(obj.InList) - # for i in obj.InList : - # print(i.TypeId) - # if hasattr(i,'Label') : - # print('Label : '+i.Label) - # if i.TypeId == 'App::Part' : - # print(i.OutList) - # for j in i.OutList : - # print(' ==> Typeid'+str(j.TypeId)) - # if hasattr(j,'Label') : - # print(' ==> Label'+j.Label) - # - #print('<<<<<') - if hasattr(obj,'InList') : - for j in obj.InList : - if hasattr(j,'OutList') : - ln = len(j.OutList) - r = indexBoolean(j.OutList,ln) - #print('index : '+str(r)) - if r >= 0 : - if (ln - r) >= 2 : - #print('Tool : '+obj.Label) - return # Let Placement default to 0 - obj.setEditorMode('Placement',2) - - def getMaterial(self): - return obj.material - - def execute(self, fp): - self.createGeometry(fp) - - def __getstate__(self): - '''When saving the document this object gets stored using Python's json module.\ - Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\ - to return a tuple of all serializable objects or None.''' - if hasattr(self,'Type') : - return {'type' : self.Type } - else : - pass - - def __setstate__(self, arg): - '''When restoring the serialized object from document we have the chance to set some internals here. Since no data were serialized nothing needs to be done here.''' - self.Type = arg['type'] - -class GDMLcommon : - def __init__(self, obj): - '''Init''' - - def __getstate__(self): - '''When saving the document this object gets stored using Python's json module.\ - Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\ - to return a tuple of all serializable objects or None.''' - if hasattr(self,'Type') : # If not saved just return - return {'type' : self.Type } - else : - pass - - def __setstate__(self,arg): - '''When restoring the serialized object from document we have the chance to set some internals here.\ - Since no data were serialized nothing needs to be done here.''' - if arg is not None : - self.Type = arg['type'] - -class GDMLArb8(GDMLsolid) : # Thanks to Dam Lamb - def __init__(self, obj, v1x, v1y, v2x, v2y, v3x, v3y, v4x, v4y, \ - v5x, v5y, v6x, v6y, v7x, v7y, v8x, v8y, dz, \ - lunit, material, colour = None): - '''Add some custom properties to our Tube feature''' - obj.addProperty("App::PropertyFloat","v1x","GDMLArb8","vertex 1 x position").v1x=v1x - obj.addProperty("App::PropertyFloat","v1y","GDMLArb8","vertex 1 y position").v1y=v1y - obj.addProperty("App::PropertyFloat","v2x","GDMLArb8","vertex 2 x position").v2x=v2x - obj.addProperty("App::PropertyFloat","v2y","GDMLArb8","vertex 2 y position").v2y=v2y - obj.addProperty("App::PropertyFloat","v3x","GDMLArb8","vertex 3 x position").v3x=v3x - obj.addProperty("App::PropertyFloat","v3y","GDMLArb8","vertex 3 y position").v3y=v3y - obj.addProperty("App::PropertyFloat","v4x","GDMLArb8","vertex 4 x position").v4x=v4x - obj.addProperty("App::PropertyFloat","v4y","GDMLArb8","vertex 4 y position").v4y=v4y - obj.addProperty("App::PropertyFloat","v5x","GDMLArb8","vertex 5 x position").v5x=v5x - obj.addProperty("App::PropertyFloat","v5y","GDMLArb8","vertex 5 y position").v5y=v5y - obj.addProperty("App::PropertyFloat","v6x","GDMLArb8","vertex 6 x position").v6x=v6x - obj.addProperty("App::PropertyFloat","v6y","GDMLArb8","vertex 6 y position").v6y=v6y - obj.addProperty("App::PropertyFloat","v7x","GDMLArb8","vertex 7 x position").v7x=v7x - obj.addProperty("App::PropertyFloat","v7y","GDMLArb8","vertex 7 y position").v7y=v7y - obj.addProperty("App::PropertyFloat","v8x","GDMLArb8","vertex 8 x position").v8x=v8x - obj.addProperty("App::PropertyFloat","v8y","GDMLArb8","vertex 8 y position").v8y=v8y - obj.addProperty("App::PropertyFloat","dz","GDMLArb8","Half z Length").dz=dz - obj.addProperty("App::PropertyEnumeration","lunit","GDMLArb8","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLArb8","Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - obj.Proxy = self - self.Type = 'GDMLArb8' - self.colour = colour - - def onChanged(self, fp, prop): - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['v1x', 'v1y', 'v2x','v2y', 'v3x', 'v3y', 'v4x', 'v4y', \ - 'v5x', 'v5y', 'v6x', 'v6y', 'v7x', 'v7y', 'v8x', 'v8y', 'dz','lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid + + +class GDMLColourMapEntry: + def __init__(self, obj, colour, material): + obj.addProperty("App::PropertyColor", "colour", + "GDMLColourMapEntry", "colour").colour = colour + obj.addProperty("App::PropertyEnumeration", "material", + "GDMLColourMapEntry", "Material") + setMaterial(obj, material) + + +def indexBoolean(list, ln): + # print('Length : '+str(ln)) + if ln > 3: + # print(range(ln-3)) + for r in range(ln-2, -1, -1): + t = list[r].TypeId + # print(t) + if t == 'Part::Cut' or t == 'Part::Fuse' or t == 'Part::Common': + return r + return -1 + + +class GDMLsolid: + def __init__(self, obj): + '''Init''' + # print('>>>>>') + # if hasattr(obj,'Label') : + # print('Label : '+obj.Label) + # print('TypeId : '+obj.TypeId) + # print(dir(obj)) + # if hasattr(obj,'InList') : + # print('InList') + # print(obj.InList) + # for i in obj.InList : + # print(i.TypeId) + # if hasattr(i,'Label') : + # print('Label : '+i.Label) + # if i.TypeId == 'App::Part' : + # print(i.OutList) + # for j in i.OutList : + # print(' ==> Typeid'+str(j.TypeId)) + # if hasattr(j,'Label') : + # print(' ==> Label'+j.Label) + # + # print('<<<<<') + if hasattr(obj, 'InList'): + for j in obj.InList: + if hasattr(j, 'OutList'): + ln = len(j.OutList) + r = indexBoolean(j.OutList, ln) + # print('index : '+str(r)) + if r >= 0: + if (ln - r) >= 2: + # print('Tool : '+obj.Label) + return # Let Placement default to 0 + obj.setEditorMode('Placement', 2) + + def getMaterial(self): + return obj.material + + def execute(self, fp): + self.createGeometry(fp) + + def __getstate__(self): + '''When saving the document this object gets stored using Python's json + module. + Since we have some un-serializable parts here -- the Coin stuff -- + we must define this method\ + to return a tuple of all serializable objects or None.''' + if hasattr(self, 'Type'): + return {'type': self.Type} + else: + pass + + def __setstate__(self, arg): + '''When restoring the serialized object from document we have the + chance to set some internals here. Since no data were serialized + nothing needs to be done here.''' + self.Type = arg['type'] + + +class GDMLcommon: + def __init__(self, obj): + '''Init''' + + def __getstate__(self): + '''When saving the document this object gets stored using Python's + json module. + Since we have some un-serializable parts here -- the Coin stuff -- + we must define this method + to return a tuple of all serializable objects or None.''' + if hasattr(self, 'Type'): # If not saved just return + return {'type': self.Type} + else: + pass + + def __setstate__(self, arg): + '''When restoring the serialized object from document we have the + chance to set some internals here. + Since no data were serialized nothing needs to be done here.''' + if arg is not None: + self.Type = arg['type'] + + +class GDMLArb8(GDMLsolid): # Thanks to Dam Lamb + def __init__(self, obj, v1x, v1y, v2x, v2y, v3x, v3y, v4x, v4y, + v5x, v5y, v6x, v6y, v7x, v7y, v8x, v8y, dz, + lunit, material, colour=None): + '''Add some custom properties to our Tube feature''' + obj.addProperty("App::PropertyFloat", + "v1x", "GDMLArb8", "vertex 1 x position").v1x = v1x + obj.addProperty("App::PropertyFloat", + "v1y", "GDMLArb8", "vertex 1 y position").v1y = v1y + obj.addProperty("App::PropertyFloat", + "v2x", "GDMLArb8", "vertex 2 x position").v2x = v2x + obj.addProperty("App::PropertyFloat", + "v2y", "GDMLArb8", "vertex 2 y position").v2y = v2y + obj.addProperty("App::PropertyFloat", + "v3x", "GDMLArb8", "vertex 3 x position").v3x = v3x + obj.addProperty("App::PropertyFloat", + "v3y", "GDMLArb8", "vertex 3 y position").v3y = v3y + obj.addProperty("App::PropertyFloat", + "v4x", "GDMLArb8", "vertex 4 x position").v4x = v4x + obj.addProperty("App::PropertyFloat", + "v4y", "GDMLArb8", "vertex 4 y position").v4y = v4y + obj.addProperty("App::PropertyFloat", + "v5x", "GDMLArb8", "vertex 5 x position").v5x = v5x + obj.addProperty("App::PropertyFloat", + "v5y", "GDMLArb8", "vertex 5 y position").v5y = v5y + obj.addProperty("App::PropertyFloat", + "v6x", "GDMLArb8", "vertex 6 x position").v6x = v6x + obj.addProperty("App::PropertyFloat", + "v6y", "GDMLArb8", "vertex 6 y position").v6y = v6y + obj.addProperty("App::PropertyFloat", + "v7x", "GDMLArb8", "vertex 7 x position").v7x = v7x + obj.addProperty("App::PropertyFloat", + "v7y", "GDMLArb8", "vertex 7 y position").v7y = v7y + obj.addProperty("App::PropertyFloat", + "v8x", "GDMLArb8", "vertex 8 x position").v8x = v8x + obj.addProperty("App::PropertyFloat", + "v8y", "GDMLArb8", "vertex 8 y position").v8y = v8y + obj.addProperty("App::PropertyFloat", + "dz", "GDMLArb8", "Half z Length").dz = dz + obj.addProperty("App::PropertyEnumeration", + "lunit", "GDMLArb8", "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", + "material", "GDMLArb8", "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + obj.Proxy = self + self.Type = 'GDMLArb8' + self.colour = colour + + def onChanged(self, fp, prop): + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['v1x', 'v1y', 'v2x', 'v2y', 'v3x', 'v3y', 'v4x', 'v4y', + 'v5x', 'v5y', 'v6x', 'v6y', 'v7x', 'v7y', 'v8x', 'v8y', + 'dz', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid # http://geant4-userdoc.web.cern.ch/geant4-userdoc/UsersGuides/ForApplicationDeveloper/html/Detector/Geometry/geomSolids.html # The order of specification of the coordinates for the vertices in G4GenericTrap is important. The first four points are the vertices sitting on the -hz plane; the last four points are the vertices sitting on the +hz plane. @@ -438,3092 +492,3170 @@ def onChanged(self, fp, prop): # point 6 is connected with points 2,5,7 # point 7 is connected with points 3,4,6 - def createGeometry(self,fp): + def createGeometry(self, fp): currPlacement = fp.Placement - mul = GDMLShared.getMult(fp) - - pt1 = FreeCAD.Vector(fp.v1x*mul,fp.v1y*mul,-fp.dz*mul) - pt2 = FreeCAD.Vector(fp.v2x*mul,fp.v2y*mul,-fp.dz*mul) - pt3 = FreeCAD.Vector(fp.v3x*mul,fp.v3y*mul,-fp.dz*mul) - pt4 = FreeCAD.Vector(fp.v4x*mul,fp.v4y*mul,-fp.dz*mul) - pt5 = FreeCAD.Vector(fp.v5x*mul,fp.v5y*mul,fp.dz*mul) - pt6 = FreeCAD.Vector(fp.v6x*mul,fp.v6y*mul,fp.dz*mul) - pt7 = FreeCAD.Vector(fp.v7x*mul,fp.v7y*mul,fp.dz*mul) - pt8 = FreeCAD.Vector(fp.v8x*mul,fp.v8y*mul,fp.dz*mul) - - faceZmin = Part.Face(Part.makePolygon([pt1,pt2,pt3,pt4,pt1])) - faceZmax = Part.Face(Part.makePolygon([pt5,pt6,pt7,pt8,pt5])) - - faceXminA = Part.Face(Part.makePolygon([pt1,pt2,pt6,pt1])) - faceXminB = Part.Face(Part.makePolygon([pt6,pt5,pt1,pt6])) - faceXmaxA = Part.Face(Part.makePolygon([pt4,pt3,pt7,pt4])) - faceXmaxB = Part.Face(Part.makePolygon([pt8,pt4,pt7,pt8])) - - faceYminA = Part.Face(Part.makePolygon([pt1,pt8,pt4,pt1])) - faceYminB = Part.Face(Part.makePolygon([pt1,pt5,pt8,pt1])) - - faceYmaxA = Part.Face(Part.makePolygon([pt2,pt3,pt7,pt2])) - faceYmaxB = Part.Face(Part.makePolygon([pt2,pt7,pt6,pt2])) - - - fp.Shape = Part.makeSolid(Part.makeShell([faceXminA,faceXminB,faceXmaxA,faceXmaxB, - faceYminA,faceYminB,faceYmaxA,faceYmaxB, - faceZmin,faceZmax])) - fp.Placement = currPlacement - -class GDMLBox(GDMLsolid) : - def __init__(self, obj, x, y, z, lunit, material, colour=None): - super().__init__(obj) - '''Add some custom properties to our Box feature''' - GDMLShared.trace("GDMLBox init") - #GDMLShared.trace("material : "+material) - obj.addProperty("App::PropertyFloat","x","GDMLBox","Length x").x=x - obj.addProperty("App::PropertyFloat","y","GDMLBox","Length y").y=y - obj.addProperty("App::PropertyFloat","z","GDMLBox","Length z").z=z - obj.addProperty("App::PropertyEnumeration","lunit","GDMLBox","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLBox","Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLBox' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - # Changing Shape in createGeometry will redrive onChanged - if ('Restore' in fp.State) : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['x','y','z','lunit'] : - self.createGeometry(fp) - - # execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - #print('createGeometry') - #print(fp) - - if all((fp.x,fp.y,fp.z)) : - currPlacement = fp.Placement - - #if (hasattr(fp,'x') and hasattr(fp,'y') and hasattr(fp,'z')) : - mul = GDMLShared.getMult(fp) - GDMLShared.trace('mul : '+str(mul)) - x = mul * fp.x - y = mul * fp.y - z = mul * fp.z - box = Part.makeBox(x,y,z) - base = FreeCAD.Vector(-x/2,-y/2,-z/2) - fp.Shape = translate(box,base) - fp.Placement = currPlacement - - def OnDocumentRestored(self,obj) : - print('Doc Restored') - - -class GDMLCone(GDMLsolid) : - def __init__(self, obj, rmin1,rmax1,rmin2,rmax2,z,startphi,deltaphi,aunit, \ - lunit, material, colour = None): - super().__init__(obj) - '''Add some custom properties to our Cone feature''' - obj.addProperty("App::PropertyFloat","rmin1","GDMLCone","Min Radius 1").rmin1=rmin1 - obj.addProperty("App::PropertyFloat","rmax1","GDMLCone","Max Radius 1").rmax1=rmax1 - obj.addProperty("App::PropertyFloat","rmin2","GDMLCone","Min Radius 2").rmin2=rmin2 - obj.addProperty("App::PropertyFloat","rmax2","GDMLCone","Max Radius 2").rmax2=rmax2 - obj.addProperty("App::PropertyFloat","z","GDMLCone","Height of Cone").z=z - obj.addProperty("App::PropertyFloat","startphi","GDMLCone","Start Angle").startphi=startphi - obj.addProperty("App::PropertyFloat","deltaphi","GDMLCone","Delta Angle").deltaphi=deltaphi - obj.addProperty("App::PropertyEnumeration","aunit","GDMLCone","aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLCone","lunit") - setLengthQuantity(obj, lunit) - - - obj.addProperty("App::PropertyEnumeration","material","GDMLCone", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLCone' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['rmin1','rmax1','rmin2','rmax2','z','startphi','deltaphi' \ - ,'aunit', 'lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - #print("fp : ") - #print(vars(fp)) - #if all((fp.rmin1,fp.rmin2,fp.rmax1,fp.rmax2,fp.z)) : - if (hasattr(fp,'rmin1') and hasattr(fp,'rmax1') and \ - hasattr(fp,'rmin2') and hasattr(fp,'rmax2') and \ - hasattr(fp,'z')) : - # Need to add code to check variables will make a valid cone - # i.e.max > min etc etc - #print("execute cone") - currPlacement = fp.Placement - mul = GDMLShared.getMult(fp) - rmin1 = mul * fp.rmin1 - rmin2 = mul * fp.rmin2 - rmax1 = mul * fp.rmax1 - rmax2 = mul * fp.rmax2 - z = mul * fp.z - #print(mul) - #print(rmax1) - #print(rmax2) - #print(rmin1) - #print(rmin2) - #print(z) - if rmax1 != rmax2 : - cone1 = Part.makeCone(rmax1,rmax2,z) - else : - cone1 = Part.makeCylinder(rmax1,z) - - if (rmin1 != 0 and rmin2 != 0 ) : - if rmin1 != rmin2 : - cone2 = Part.makeCone(rmin1,rmin2,z) - else : - cone2 = Part.makeCylinder(rmin1,z) - - if rmax1 > rmin1 : - cone3 = cone1.cut(cone2) - else : - cone3 = cone2.cut(cone1) - else : - cone3 = cone1 - base = FreeCAD.Vector(0,0,-z/2) - if checkFullCircle(fp.aunit,fp.deltaphi) == False : - rmax = max(rmax1, rmax2) - cone = angleSectionSolid(fp, rmax, z, cone3) - fp.Shape = translate(cone,base) - else : - fp.Shape = translate(cone3,base) - fp.Placement = currPlacement - -class GDMLElCone(GDMLsolid) : - def __init__(self, obj, dx, dy, zmax, zcut, lunit, material, colour = None) : - super().__init__(obj) - '''Add some custom properties to our ElCone feature''' - obj.addProperty("App::PropertyFloat","dx","GDMLElCone", \ - "x semi axis").dx = dx - obj.addProperty("App::PropertyFloat","dy","GDMLElCone", \ - "y semi axis").dy = dy - obj.addProperty("App::PropertyFloat","zmax","GDMLElCone", \ - "z length").zmax = zmax - obj.addProperty("App::PropertyFloat","zcut","GDMLElCone", \ - "z cut").zcut = zcut - obj.addProperty("App::PropertyEnumeration","lunit","GDMLElCone","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLElCone", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLElCone' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['dx','dy','zmax','zcut','lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - # Form the Web page documentation page for elliptical cone: - #https://geant4-userdoc.web.cern.ch/UsersGuides/ForApplicationDeveloper/html/Detector/Geometry/geomSolids.html - # the parametric equation of the elliptical cone: - # x = dx*(zmax - u) * cos(v), v = 0..2Pi (note, as of 2021-11-21, web page mistakingly shows /u) - # y = dy*(zmax - u) * sin(v) - # z = u, u = -zcut..zcut - #Therefore the bottom base of the cone (at z=u=-zcut) has xmax = dxmax = dx*(zmax+zcut) - # and ymax=dymax = dy*(zmax+zcut) - # The ellipse at the top has simi-major axis dx*(zmax-zcut) and semiminor axis dy*(zmax-zcut) - # as per the above, the "bottom of the cone is at z = -zcut - # Note that dx is a SCALING factor for the semi major axis, NOT the actual semi major axis - # ditto for dy - - mul = GDMLShared.getMult(fp) - currPlacement = fp.Placement - rmax = (fp.zmax+fp.zcut)*mul - cone1 = Part.makeCone(rmax, 0, rmax) - mat = FreeCAD.Matrix() - mat.unity() - # Semi axis values so need to double - dx = fp.dx - dy = fp.dy - zcut = fp.zcut * mul - zmax = fp.zmax * mul - mat.A11 = dx - mat.A22 = dy - mat.A33 = 1 - mat.A34 = -zcut # move bottom of cone to -zcut - mat.A44 = 1 - xmax = dx*rmax - ymax = dy*rmax - cone2 = cone1.transformGeometry(mat) - if zcut is not None : - box = Part.makeBox(2*xmax,2*ymax,zmax) - pl = FreeCAD.Placement() - # Only need to move to semi axis - pl.move(FreeCAD.Vector(-xmax,- ymax, zcut)) - box.Placement = pl - fp.Shape = cone2.cut(box) - else : - fp.Shape = cone2 - fp.Placement = currPlacement - -class GDMLEllipsoid(GDMLsolid) : - def __init__(self, obj, ax, by, cz, zcut1, zcut2, lunit, material, colour = None) : - super().__init__(obj) - '''Add some custom properties to our Elliptical Tube feature''' - obj.addProperty("App::PropertyFloat","ax","GDMLEllipsoid", \ - "x semi axis").ax=ax - obj.addProperty("App::PropertyFloat","by","GDMLEllipsoid", \ - "y semi axis").by=by - obj.addProperty("App::PropertyFloat","cz","GDMLEllipsoid", \ - "z semi axis").cz=cz - obj.addProperty("App::PropertyFloat","zcut1","GDMLEllipsoid", \ - "z axis cut1").zcut1=zcut1 - obj.addProperty("App::PropertyFloat","zcut2","GDMLEllipsoid", \ - "z axis1 cut2").zcut2=zcut2 - obj.addProperty("App::PropertyEnumeration","lunit","GDMLEllipsoid","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLEllipsoid", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLEllipsoid' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['ax','by','cz','zcut1','zcut2','lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - mul = GDMLShared.getMult(fp) - sphere = Part.makeSphere(100) - ax = fp.ax * mul - by = fp.by * mul - cz = fp.cz * mul - mat = FreeCAD.Matrix() - mat.unity() - # Semi axis values so need to double - mat.A11 = ax / 50 - mat.A22 = by / 50 - mat.A33 = cz / 50 - mat.A44 = 1 - zcut1 = abs(fp.zcut1*mul) - zcut2 = abs(fp.zcut2*mul) - GDMLShared.trace("zcut2 : "+str(zcut2)) - t1ellipsoid = sphere.transformGeometry(mat) - if zcut2 is not None and zcut2 > 0 and zcut2 < cz: # Remove from upper z - box1 = Part.makeBox(2*ax,2*by,zcut2) - pl = FreeCAD.Placement() - # Only need to move to semi axis - pl.move(FreeCAD.Vector(-ax,-by,cz-zcut2)) - box1.Placement = pl - t2ellipsoid = t1ellipsoid.cut(box1) - else : - t2ellipsoid = t1ellipsoid - if zcut1 is not None and zcut1 > 0 and zcut1 < cz: - # Remove from lower z, seems to be a negative number - box2 = Part.makeBox(2*ax,2*by,zcut1) - pl = FreeCAD.Placement() - pl.move(FreeCAD.Vector(-ax,-by,-cz)) - box2.Placement = pl - shape = t2ellipsoid.cut(box2) - else : - shape = t2ellipsoid - - base = FreeCAD.Vector(0,0,cz/4) - fp.Shape = translate(shape,base) - fp.Placement = currPlacement - -class GDMLElTube(GDMLsolid) : - def __init__(self, obj, dx, dy, dz, lunit, material, colour=None) : - super().__init__(obj) - '''Add some custom properties to our Elliptical Tube feature''' - obj.addProperty("App::PropertyFloat","dx","GDMLElTube", \ - "x semi axis1").dx=dx - obj.addProperty("App::PropertyFloat","dy","GDMLElTube", \ - "y semi axis1").dy=dy - obj.addProperty("App::PropertyFloat","dz","GDMLElTube", \ - "z half height").dz=dz - obj.addProperty("App::PropertyEnumeration","lunit","GDMLElTube","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLElTube", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLElTube' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - '''Do something when a property has changed''' - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['dx','dy','dz','lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - mul = GDMLShared.getMult(fp) - tube = Part.makeCylinder(100,100) - mat = FreeCAD.Matrix() - mat.unity() - mat.A11 = (fp.dx * mul) / 100 - mat.A22 = (fp.dy * mul) / 100 - mat.A33 = (fp.dz * mul) / 50 - mat.A44 = 1 - #trace mat - newtube = tube.transformGeometry(mat) - base = FreeCAD.Vector(0,0,-(fp.dz*mul)) #dz is half height - fp.Shape = translate(newtube,base) - fp.Placement = currPlacement - -class GDMLOrb(GDMLsolid) : - def __init__(self, obj, r, lunit, material, colour=None) : - super().__init__(obj) - '''Add some custom properties for Polyhedra feature''' - obj.addProperty("App::PropertyFloat","r","GDMLOrb","Radius").r=r - obj.addProperty("App::PropertyEnumeration","lunit","GDMLOrb","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLOrb", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLOrb' - self.Object = obj - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['r', 'lunit'] : - #print(dir(fp)) - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - #GDMLShared.setTrace(True) - GDMLShared.trace("Execute Orb") - mul = GDMLShared.getMult(fp.lunit) - r = mul * fp.r - fp.Shape = Part.makeSphere(r) - fp.Placement = currPlacement - -class GDMLPara(GDMLsolid) : - def __init__(self, obj, x, y, z, alpha, theta, phi, aunit, lunit, \ - material, colour= None) : - super().__init__(obj) - '''Add some custom properties for Polyhedra feature''' - obj.addProperty("App::PropertyFloat","x","GDMLParapiped","x").x=x - obj.addProperty("App::PropertyFloat","y","GDMLParapiped","y").y=y - obj.addProperty("App::PropertyFloat","z","GDMLParapiped","z").z=z - obj.addProperty("App::PropertyFloat","alpha","GDMLParapiped", \ - "Angle with y axis").alpha=alpha - obj.addProperty("App::PropertyFloat","theta","GDMLParapiped", \ - "Polar Angle with faces").theta=theta - obj.addProperty("App::PropertyFloat","phi","GDMLParapiped", \ - "Azimuthal Angle with faces").phi=phi - obj.addProperty("App::PropertyEnumeration","aunit","GDMLParapiped", \ - "aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLParapiped","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLParapiped", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLPara' - self.colour = colour - self.Object = obj - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['x', 'y', 'z', 'alpha', 'theta', 'phi', 'aunit','lunit'] : - self.createGeometry(fp) - - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - #GDMLShared.setTrace(True) - GDMLShared.trace("Execute Polyparallepiped") - mul = GDMLShared.getMult(fp) - x = mul * fp.x - y = mul * fp.y - z = mul * fp.z - alpha = getAngleRad(fp.aunit,fp.alpha) - theta = getAngleRad(fp.aunit,fp.theta) - phi = getAngleRad(fp.aunit,fp.phi) - #Vertexes - v1 = FreeCAD.Vector( 0, 0, 0) - v2 = FreeCAD.Vector( x, 0, 0) - v3 = FreeCAD.Vector( x, y, 0) - v4 = FreeCAD.Vector( 0, y, 0) - v5 = FreeCAD.Vector( 0, 0, z) - v6 = FreeCAD.Vector( x, 0, z) - v7 = FreeCAD.Vector( x, y, z) - v8 = FreeCAD.Vector( 0, y, z) - # - # xy faces - # - vxy1 = [v1, v4, v3, v2, v1] - vxy2 = [v5, v6, v7, v8, v5] - # - # zx faces - # - vzx1 = [v1, v2, v6, v5, v1] - vzx2 = [v3, v4, v8, v7, v3] - # - # yz faces - # - vyz1 = [v5, v8, v4, v1, v5] - vyz2 = [v2, v3, v7, v6, v2] - - # Apply alpha angle distortions - # - dx = z*math.tan(alpha) - for i in range(0,4): - vzx2[i][0] += dx - # - # apply theta, phi distortions - # - rho = z*math.tan(theta) - dx = rho*math.cos(phi) - dy = rho*math.sin(phi) - for i in range(0,4): - vxy2[i][0] += dx - vxy2[i][1] += dy - - fxy1 = Part.Face(Part.makePolygon(vxy1)) - fxy2 = Part.Face(Part.makePolygon(vxy2)) - fzx1 = Part.Face(Part.makePolygon(vzx1)) - fzx2 = Part.Face(Part.makePolygon(vzx2)) - fyz1 = Part.Face(Part.makePolygon(vyz1)) - fyz2 = Part.Face(Part.makePolygon(vyz2)) - - shell = Part.makeShell([fxy1, fxy2, fzx1, fzx2, fyz1, fyz2]) - solid = Part.makeSolid(shell) - - # center is mid point of diagonal - # - center = (v7 - v1)/2 - fp.Shape = translate(solid, -center) - fp.Placement = currPlacement - -class GDMLHype(GDMLsolid) : - def __init__(self, obj, rmin, rmax, z, inst, outst, aunit, lunit, \ - material, colour= None) : - super().__init__(obj) - '''Add some custom properties for Hyperbolic Tube feature''' - obj.addProperty("App::PropertyFloat","rmin","GDMLHype","inner radius at z=0").rmin=rmin - obj.addProperty("App::PropertyFloat","rmax","GDMLHype","outer radius at z=0").rmax=rmax - obj.addProperty("App::PropertyFloat","z","GDMLHype","Tube length").z=z - obj.addProperty("App::PropertyFloat","inst","GDMLHype", \ - "Inner stereo").inst=inst - obj.addProperty("App::PropertyFloat","outst","GDMLHype", \ - "Outer stero").outst=outst - obj.addProperty("App::PropertyEnumeration","aunit","GDMLHype", \ - "aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLHype","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLHype", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLHype' - self.colour = colour - self.Object = obj - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['rmin', 'rmax', 'z', 'inst', 'outst', 'aunit','lunit'] : - self.createGeometry(fp) - - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - #GDMLShared.setTrace(True) - GDMLShared.trace("Execute Hyperbolic Tube") - # this should probably be a global variable, but - # for now adopt the value used in geant4.10.07.p02 - NUMBER_OF_DIVISIONS = 36 - mul = GDMLShared.getMult(fp) - rmin = mul * fp.rmin - rmax = mul * fp.rmax - z = mul * fp.z - inst = getAngleRad(fp.aunit,fp.inst) - outst = getAngleRad(fp.aunit,fp.outst) - sqrtan1 = math.tan(inst) - sqrtan1 *= sqrtan1 - sqrtan2 = math.tan(outst) - sqrtan2 *= sqrtan2 - - # mirroring error checking in HepPolyhedron.cc - k = 0 - if rmin < 0. or rmax < 0. or rmin >= rmax: - k = 1 - if z <= 0.: - k += 2 - - if k != 0: - errmsg = "HepPolyhedronHype: error in input parameters: " - if (k & 1) != 0: - errmsg += " (radii)" - if (k & 2) != 0: - errmsg += " (half-length)" - print(errmsg) - print(f' rmin= {rmin} rmax= {rmax} z= {z}') - return - - # Prepare two polylines - ns = NUMBER_OF_DIVISIONS - if ns < 3: - ns = 3 - if sqrtan1 == 0.: - nz1 = 2 - else: - nz1 = ns + 1 - if sqrtan2 == 0.: - nz2 = 2 - else: - nz2 = ns + 1 - - halfZ = z/2 - # - # solid generated by external hyperbeloid - dz2 = z/(nz2 - 1) - zz = [halfZ - dz2*i for i in range(0, nz2)] - rr = [math.sqrt(sqrtan2*zi*zi + rmax*rmax) for zi in zz] - outersolid = rotateAroundZ(NUMBER_OF_DIVISIONS, zz, rr) - fp.Shape = outersolid - - if rmin != 0: - # - # solid generated by internal hyperbeloid - dz1 = z/(nz1 - 1) - zz = [halfZ - dz1*i for i in range(0, nz1)] - rr = [math.sqrt(sqrtan1*zi*zi + rmin*rmin) for zi in zz] - innersolid = rotateAroundZ(NUMBER_OF_DIVISIONS, zz, rr) - fp.Shape = outersolid.cut(innersolid) - - fp.Placement = currPlacement - -class GDMLParaboloid(GDMLsolid) : - def __init__(self, obj, rlo, rhi, dz, lunit, \ - material, colour= None) : - super().__init__(obj) - '''Add some custom properties for the Paraboloid feature''' - obj.addProperty("App::PropertyFloat","rlo","GDMLParaboloid","radius at -z/2").rlo=rlo - obj.addProperty("App::PropertyFloat","rhi","GDMLParaboloid","radius at +z/2").rhi=rhi - obj.addProperty("App::PropertyFloat","dz","GDMLParaboloid","Paraboloid half length").dz=dz - obj.addProperty("App::PropertyEnumeration","lunit","GDMLParaboloid","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLParaboloid", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLParaboloid' - self.colour = colour - self.Object = obj - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['rlo', 'rhi', 'z', 'lunit'] : - self.createGeometry(fp) - - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - #GDMLShared.setTrace(True) - GDMLShared.trace("Execute Hyperbolic Tube") - # this should probably be a global variable, but - # for now adopt the value used in geant4.10.07.p02 - NUMBER_OF_DIVISIONS = 24 - mul = GDMLShared.getMult(fp) - rlo = mul * fp.rlo - rhi = mul * fp.rhi - dz = mul * fp.dz - if dz < 0 or rlo > rhi: - errmsg = "paraboloid: error in input parameters: dz < 0 and/or rlo > rhi " - print(errmsg) - print(f' rlo= {rlo} rhi= {rhi} dz= {dz}') - return - - # Prepare polylines - ns = NUMBER_OF_DIVISIONS - # paraboloid given by following equation: - # rho^2 = k1 * z + k2, (rho = distance of point on surface from z-axis) - # k1 and k2 can be obtained from requirement: - # rlo^2 = k1*(-dz) + k2 - # rhi^2 = k1*(dz) + k2 - k1 = (rhi*rhi - rlo*rlo)/(2*dz) - k2 = (rhi*rhi + rlo*rlo)/2 - # - # solid generated by external hyperbeloid - deltaz = 2*dz/(ns - 1) - zz = [dz - deltaz*i for i in range(0, ns)] - rr = [math.sqrt(k1*zi+k2) for zi in zz] - outersolid = rotateAroundZ(NUMBER_OF_DIVISIONS, zz, rr) - fp.Shape = outersolid - - fp.Placement = currPlacement - -class GDMLPolyhedra(GDMLsolid) : - def __init__(self, obj, startphi, deltaphi, numsides, aunit, lunit, \ - material, colour = None) : - super().__init__(obj) - '''Add some custom properties for Polyhedra feature''' - obj.addProperty("App::PropertyFloat","startphi","GDMLPolyhedra", \ - "Start Angle").startphi=startphi - obj.addProperty("App::PropertyFloat","deltaphi","GDMLPolyhedra", \ - "Delta Angle").deltaphi=deltaphi - obj.addProperty("App::PropertyInteger","numsides","GDMLPolyhedra", \ - "Number of Side").numsides=numsides - obj.addProperty("App::PropertyEnumeration","aunit","GDMLPolyhedra", \ - "aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLPolyhdera","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLPolyhedra", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLPolyhedra' - self.colour = colour - self.Object = obj - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['startphi', 'deltaphi', 'numsides', 'aunit','lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - #GDMLShared.setTrace(True) - GDMLShared.trace("Execute Polyhedra") - parms = fp.OutList - GDMLShared.trace("Number of parms : "+str(len(parms))) - numsides = fp.numsides - GDMLShared.trace("Number of sides : "+str(numsides)) - mul = GDMLShared.getMult(fp) - z0 = parms[0].z * mul - rmin0 = parms[0].rmin * mul - rmax0 = parms[0].rmax * mul - GDMLShared.trace("Top z : "+str(z0)) - GDMLShared.trace("Top rmin : "+str(rmin0)) - GDMLShared.trace("Top rmax : "+str(rmax0)) - inner_faces = [] - outer_faces = [] - numsides = int(numsides * 360 / getAngleDeg(fp.aunit,fp.deltaphi)) - # Deal with Inner Top Face - # Could be point rmin0 = rmax0 = 0 - if rmin0 > 0 : - inner_poly0 = makeRegularPolygon(numsides,rmin0,z0) - inner_faces.append(Part.Face(Part.makePolygon(inner_poly0))) - # Deal with Outer Top Face - outer_poly0 = makeRegularPolygon(numsides,rmax0,z0) - if rmax0 > 0 : # Only make polygon if not a point + mul = GDMLShared.getMult(fp) + + pt1 = FreeCAD.Vector(fp.v1x*mul, fp.v1y*mul, -fp.dz*mul) + pt2 = FreeCAD.Vector(fp.v2x*mul, fp.v2y*mul, -fp.dz*mul) + pt3 = FreeCAD.Vector(fp.v3x*mul, fp.v3y*mul, -fp.dz*mul) + pt4 = FreeCAD.Vector(fp.v4x*mul, fp.v4y*mul, -fp.dz*mul) + pt5 = FreeCAD.Vector(fp.v5x*mul, fp.v5y*mul, fp.dz*mul) + pt6 = FreeCAD.Vector(fp.v6x*mul, fp.v6y*mul, fp.dz*mul) + pt7 = FreeCAD.Vector(fp.v7x*mul, fp.v7y*mul, fp.dz*mul) + pt8 = FreeCAD.Vector(fp.v8x*mul, fp.v8y*mul, fp.dz*mul) + + faceZmin = Part.Face(Part.makePolygon([pt1, pt2, pt3, pt4, pt1])) + faceZmax = Part.Face(Part.makePolygon([pt5, pt6, pt7, pt8, pt5])) + + faceXminA = Part.Face(Part.makePolygon([pt1, pt2, pt6, pt1])) + faceXminB = Part.Face(Part.makePolygon([pt6, pt5, pt1, pt6])) + faceXmaxA = Part.Face(Part.makePolygon([pt4, pt3, pt7, pt4])) + faceXmaxB = Part.Face(Part.makePolygon([pt8, pt4, pt7, pt8])) + + faceYminA = Part.Face(Part.makePolygon([pt1, pt8, pt4, pt1])) + faceYminB = Part.Face(Part.makePolygon([pt1, pt5, pt8, pt1])) + + faceYmaxA = Part.Face(Part.makePolygon([pt2, pt3, pt7, pt2])) + faceYmaxB = Part.Face(Part.makePolygon([pt2, pt7, pt6, pt2])) + + fp.Shape = Part.makeSolid(Part.makeShell([faceXminA, faceXminB, + faceXmaxA, faceXmaxB, + faceYminA, faceYminB, + faceYmaxA, faceYmaxB, + faceZmin, faceZmax])) + fp.Placement = currPlacement + + +class GDMLBox(GDMLsolid): + def __init__(self, obj, x, y, z, lunit, material, colour=None): + super().__init__(obj) + '''Add some custom properties to our Box feature''' + GDMLShared.trace("GDMLBox init") + # GDMLShared.trace("material : "+material) + obj.addProperty("App::PropertyFloat", "x", "GDMLBox", "Length x").x = x + obj.addProperty("App::PropertyFloat", "y", "GDMLBox", "Length y").y = y + obj.addProperty("App::PropertyFloat", "z", "GDMLBox", "Length z").z = z + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLBox", "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLBox", "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLBox' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + # Changing Shape in createGeometry will redrive onChanged + if ('Restore' in fp.State): + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['x', 'y', 'z', 'lunit']: + self.createGeometry(fp) + + # execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + # print('createGeometry') + # print(fp) + + if all((fp.x, fp.y, fp.z)): + currPlacement = fp.Placement + + # if (hasattr(fp,'x') and hasattr(fp,'y') and hasattr(fp,'z')) : + mul = GDMLShared.getMult(fp) + GDMLShared.trace('mul : '+str(mul)) + x = mul * fp.x + y = mul * fp.y + z = mul * fp.z + box = Part.makeBox(x, y, z) + base = FreeCAD.Vector(-x/2, -y/2, -z/2) + fp.Shape = translate(box, base) + fp.Placement = currPlacement + + def OnDocumentRestored(self, obj): + print('Doc Restored') + + +class GDMLCone(GDMLsolid): + def __init__(self, obj, rmin1, rmax1, rmin2, + rmax2, z, startphi, deltaphi, aunit, + lunit, material, colour=None): + super().__init__(obj) + '''Add some custom properties to our Cone feature''' + obj.addProperty("App::PropertyFloat", + "rmin1", "GDMLCone", "Min Radius 1").rmin1 = rmin1 + obj.addProperty("App::PropertyFloat", + "rmax1", "GDMLCone", "Max Radius 1").rmax1 = rmax1 + obj.addProperty("App::PropertyFloat", + "rmin2", "GDMLCone", "Min Radius 2").rmin2 = rmin2 + obj.addProperty("App::PropertyFloat", + "rmax2", "GDMLCone", "Max Radius 2").rmax2 = rmax2 + obj.addProperty("App::PropertyFloat", + "z", "GDMLCone", "Height of Cone").z = z + obj.addProperty("App::PropertyFloat", + "startphi", "GDMLCone", "Start Angle").startphi = startphi + obj.addProperty("App::PropertyFloat", + "deltaphi","GDMLCone", "Delta Angle").deltaphi = deltaphi + obj.addProperty("App::PropertyEnumeration", + "aunit", "GDMLCone", "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLCone", "lunit") + setLengthQuantity(obj, lunit) + + obj.addProperty("App::PropertyEnumeration", "material", "GDMLCone", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLCone' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['rmin1', 'rmax1', 'rmin2', 'rmax2', + 'z', 'startphi', 'deltaphi', + 'aunit', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + # print("fp : ") + # print(vars(fp)) + # if all((fp.rmin1,fp.rmin2,fp.rmax1,fp.rmax2,fp.z)) : + if (hasattr(fp, 'rmin1') and hasattr(fp, 'rmax1') and + hasattr(fp, 'rmin2') and hasattr(fp, 'rmax2') and + hasattr(fp, 'z')): + # Need to add code to check variables will make a valid cone + # i.e.max > min etc etc + # print("execute cone") + currPlacement = fp.Placement + mul = GDMLShared.getMult(fp) + rmin1 = mul * fp.rmin1 + rmin2 = mul * fp.rmin2 + rmax1 = mul * fp.rmax1 + rmax2 = mul * fp.rmax2 + z = mul * fp.z + # print(mul) + # print(rmax1) + # print(rmax2) + # print(rmin1) + # print(rmin2) + # print(z) + if rmax1 != rmax2: + cone1 = Part.makeCone(rmax1, rmax2, z) + else: + cone1 = Part.makeCylinder(rmax1, z) + + if (rmin1 != 0 and rmin2 != 0): + if rmin1 != rmin2: + cone2 = Part.makeCone(rmin1, rmin2, z) + else: + cone2 = Part.makeCylinder(rmin1, z) + + if rmax1 > rmin1: + cone3 = cone1.cut(cone2) + else: + cone3 = cone2.cut(cone1) + else: + cone3 = cone1 + base = FreeCAD.Vector(0, 0, -z/2) + if checkFullCircle(fp.aunit, fp.deltaphi) is False: + rmax = max(rmax1, rmax2) + cone = angleSectionSolid(fp, rmax, z, cone3) + fp.Shape = translate(cone, base) + else: + fp.Shape = translate(cone3, base) + fp.Placement = currPlacement + + +class GDMLElCone(GDMLsolid): + def __init__(self, obj, dx, dy, zmax, zcut, lunit, material, colour=None): + super().__init__(obj) + '''Add some custom properties to our ElCone feature''' + obj.addProperty("App::PropertyFloat", "dx", "GDMLElCone", + "x semi axis").dx = dx + obj.addProperty("App::PropertyFloat", "dy", "GDMLElCone", + "y semi axis").dy = dy + obj.addProperty("App::PropertyFloat", "zmax", "GDMLElCone", + "z length").zmax = zmax + obj.addProperty("App::PropertyFloat", "zcut", "GDMLElCone", + "z cut").zcut = zcut + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLElCone", "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLElCone", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLElCone' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['dx', 'dy', 'zmax', 'zcut', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + # Form the Web page documentation page for elliptical cone: + # https://geant4-userdoc.web.cern.ch/UsersGuides/ForApplicationDeveloper/html/Detector/Geometry/geomSolids.html + # the parametric equation of the elliptical cone: + # x = dx*(zmax - u) * cos(v), v = 0..2Pi (note, as of 2021-11-21, + # web page mistakingly shows /u) + # y = dy*(zmax - u) * sin(v) + # z = u, u = -zcut..zcut + # Therefore the bottom base of the cone (at z=u=-zcut) has + # xmax = dxmax = dx*(zmax+zcut) + # and ymax=dymax = dy*(zmax+zcut) + # The ellipse at the top has simi-major axis dx*(zmax-zcut) and + # semiminor axis dy*(zmax-zcut) + # as per the above, the "bottom of the cone is at z = -zcut + # Note that dx is a SCALING factor for the semi major axis, + # NOT the actual semi major axis + # ditto for dy + + mul = GDMLShared.getMult(fp) + currPlacement = fp.Placement + rmax = (fp.zmax+fp.zcut)*mul + cone1 = Part.makeCone(rmax, 0, rmax) + mat = FreeCAD.Matrix() + mat.unity() + # Semi axis values so need to double + dx = fp.dx + dy = fp.dy + zcut = fp.zcut * mul + zmax = fp.zmax * mul + mat.A11 = dx + mat.A22 = dy + mat.A33 = 1 + mat.A34 = -zcut # move bottom of cone to -zcut + mat.A44 = 1 + xmax = dx*rmax + ymax = dy*rmax + cone2 = cone1.transformGeometry(mat) + if zcut is not None: + box = Part.makeBox(2*xmax, 2*ymax, zmax) + pl = FreeCAD.Placement() + # Only need to move to semi axis + pl.move(FreeCAD.Vector(-xmax, -ymax, zcut)) + box.Placement = pl + fp.Shape = cone2.cut(box) + else: + fp.Shape = cone2 + fp.Placement = currPlacement + + +class GDMLEllipsoid(GDMLsolid): + def __init__(self, obj, ax, by, cz, zcut1, zcut2, lunit, material, colour=None): + super().__init__(obj) + '''Add some custom properties to our Elliptical Tube feature''' + obj.addProperty("App::PropertyFloat", "ax", "GDMLEllipsoid", + "x semi axis").ax = ax + obj.addProperty("App::PropertyFloat", "by", "GDMLEllipsoid", + "y semi axis").by = by + obj.addProperty("App::PropertyFloat", "cz", "GDMLEllipsoid", + "z semi axis").cz = cz + obj.addProperty("App::PropertyFloat", "zcut1", "GDMLEllipsoid", + "z axis cut1").zcut1 = zcut1 + obj.addProperty("App::PropertyFloat", "zcut2", "GDMLEllipsoid", + "z axis1 cut2").zcut2 = zcut2 + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLEllipsoid", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLEllipsoid", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLEllipsoid' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['ax', 'by', 'cz', 'zcut1', 'zcut2', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + mul = GDMLShared.getMult(fp) + sphere = Part.makeSphere(100) # 100= sphere radius = 1/2 diameter + ax = fp.ax * mul + by = fp.by * mul + cz = fp.cz * mul + mat = FreeCAD.Matrix() + mat.unity() + + mat.A11 = ax / 100 + mat.A22 = by / 100 + mat.A33 = cz / 100 + mat.A44 = 1 + + if fp.zcut1 is not None: + zcut1 = fp.zcut1*mul + else: + zcut1 = -2*cz + + if fp.zcut2 is not None: + zcut2 = fp.zcut2*mul + else: + zcut2 = 2*cz + + GDMLShared.trace("zcut2 : " + str(zcut2)) + t1ellipsoid = sphere.transformGeometry(mat) + if zcut2 > -cz and zcut2 < cz: # Remove from upper z + box1 = Part.makeBox(2*ax, 2*by, 2*cz) + pl = FreeCAD.Placement() + # Only need to move to semi axis + pl.move(FreeCAD.Vector(-ax, -by, zcut2)) + box1.Placement = pl + t2ellipsoid = t1ellipsoid.cut(box1) + else: + t2ellipsoid = t1ellipsoid + if zcut1 < zcut2 and zcut1 > -cz and zcut1 < cz: + box2 = Part.makeBox(2*ax, 2*by, 2*cz) + pl = FreeCAD.Placement() + # cut with the upper edge of the box + pl.move(FreeCAD.Vector(-ax, -by, -2*cz+zcut1)) + box2.Placement = pl + shape = t2ellipsoid.cut(box2) + else: + shape = t2ellipsoid + + base = FreeCAD.Vector(0, 0, 0) + fp.Shape = translate(shape, base) + fp.Placement = currPlacement + + +class GDMLElTube(GDMLsolid): + def __init__(self, obj, dx, dy, dz, lunit, material, colour=None): + super().__init__(obj) + '''Add some custom properties to our Elliptical Tube feature''' + obj.addProperty("App::PropertyFloat", "dx", "GDMLElTube", + "x semi axis1").dx = dx + obj.addProperty("App::PropertyFloat", "dy", "GDMLElTube", + "y semi axis1").dy = dy + obj.addProperty("App::PropertyFloat", "dz", "GDMLElTube", + "z half height").dz = dz + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLElTube", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLElTube", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLElTube' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + '''Do something when a property has changed''' + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['dx', 'dy', 'dz', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + mul = GDMLShared.getMult(fp) + tube = Part.makeCylinder(100, 100) + mat = FreeCAD.Matrix() + mat.unity() + mat.A11 = (fp.dx * mul) / 100 + mat.A22 = (fp.dy * mul) / 100 + mat.A33 = (fp.dz * mul) / 50 + mat.A44 = 1 + # trace mat + newtube = tube.transformGeometry(mat) + base = FreeCAD.Vector(0, 0, -(fp.dz*mul)) # dz is half height + fp.Shape = translate(newtube, base) + fp.Placement = currPlacement + + +class GDMLOrb(GDMLsolid): + def __init__(self, obj, r, lunit, material, colour=None): + super().__init__(obj) + '''Add some custom properties for Polyhedra feature''' + obj.addProperty("App::PropertyFloat", "r", "GDMLOrb", "Radius").r = r + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLOrb", "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLOrb", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLOrb' + self.Object = obj + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['r', 'lunit']: + # print(dir(fp)) + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + # GDMLShared.setTrace(True) + GDMLShared.trace("Execute Orb") + mul = GDMLShared.getMult(fp.lunit) + r = mul * fp.r + fp.Shape = Part.makeSphere(r) + fp.Placement = currPlacement + + +class GDMLPara(GDMLsolid): + def __init__(self, obj, x, y, z, alpha, theta, phi, aunit, lunit, + material, colour=None): + super().__init__(obj) + '''Add some custom properties for Polyhedra feature''' + obj.addProperty("App::PropertyFloat", "x", "GDMLParapiped", "x").x = x + obj.addProperty("App::PropertyFloat", "y", "GDMLParapiped", "y").y = y + obj.addProperty("App::PropertyFloat", "z", "GDMLParapiped", "z").z = z + obj.addProperty("App::PropertyFloat", "alpha", "GDMLParapiped", + "Angle with y axis").alpha = alpha + obj.addProperty("App::PropertyFloat", "theta", "GDMLParapiped", + "Polar Angle with faces").theta = theta + obj.addProperty("App::PropertyFloat", "phi", "GDMLParapiped", + "Azimuthal Angle with faces").phi = phi + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLParapiped", + "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLParapiped", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLParapiped", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLPara' + self.colour = colour + self.Object = obj + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['x', 'y', 'z', 'alpha', 'theta', 'phi', 'aunit', 'lunit']: + self.createGeometry(fp) + + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + #GDMLShared.setTrace(True) + GDMLShared.trace("Execute Polyparallepiped") + mul = GDMLShared.getMult(fp) + x = mul * fp.x + y = mul * fp.y + z = mul * fp.z + alpha = getAngleRad(fp.aunit, fp.alpha) + theta = getAngleRad(fp.aunit, fp.theta) + phi = getAngleRad(fp.aunit, fp.phi) + # Vertexes + v1 = FreeCAD.Vector(0, 0, 0) + v2 = FreeCAD.Vector(x, 0, 0) + v3 = FreeCAD.Vector(x, y, 0) + v4 = FreeCAD.Vector(0, y, 0) + v5 = FreeCAD.Vector(0, 0, z) + v6 = FreeCAD.Vector(x, 0, z) + v7 = FreeCAD.Vector(x, y, z) + v8 = FreeCAD.Vector(0, y, z) + # + # xy faces + # + vxy1 = [v1, v4, v3, v2, v1] + vxy2 = [v5, v6, v7, v8, v5] + # + # zx faces + # + vzx1 = [v1, v2, v6, v5, v1] + vzx2 = [v3, v4, v8, v7, v3] + # + # yz faces + # + vyz1 = [v5, v8, v4, v1, v5] + vyz2 = [v2, v3, v7, v6, v2] + + # Apply alpha angle distortions + # + dx = z*math.tan(alpha) + for i in range(0, 4): + vzx2[i][0] += dx + # + # apply theta, phi distortions + # + rho = z*math.tan(theta) + dx = rho*math.cos(phi) + dy = rho*math.sin(phi) + for i in range(0, 4): + vxy2[i][0] += dx + vxy2[i][1] += dy + + fxy1 = Part.Face(Part.makePolygon(vxy1)) + fxy2 = Part.Face(Part.makePolygon(vxy2)) + fzx1 = Part.Face(Part.makePolygon(vzx1)) + fzx2 = Part.Face(Part.makePolygon(vzx2)) + fyz1 = Part.Face(Part.makePolygon(vyz1)) + fyz2 = Part.Face(Part.makePolygon(vyz2)) + + shell = Part.makeShell([fxy1, fxy2, fzx1, fzx2, fyz1, fyz2]) + solid = Part.makeSolid(shell) + + # center is mid point of diagonal + # + center = (v7 - v1)/2 + fp.Shape = translate(solid, -center) + fp.Placement = currPlacement + + +class GDMLHype(GDMLsolid): + def __init__(self, obj, rmin, rmax, z, inst, outst, aunit, lunit, + material, colour=None): + super().__init__(obj) + '''Add some custom properties for Hyperbolic Tube feature''' + obj.addProperty("App::PropertyFloat", "rmin", "GDMLHype", + "inner radius at z=0").rmin = rmin + obj.addProperty("App::PropertyFloat", "rmax", "GDMLHype", + "outer radius at z=0").rmax = rmax + obj.addProperty("App::PropertyFloat", "z", "GDMLHype", + "Tube length").z = z + obj.addProperty("App::PropertyFloat", "inst", "GDMLHype", + "Inner stereo").inst = inst + obj.addProperty("App::PropertyFloat", "outst", "GDMLHype", + "Outer stero").outst = outst + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLHype", + "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLHype", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLHype", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLHype' + self.colour = colour + self.Object = obj + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['rmin', 'rmax', 'z', 'inst', 'outst', 'aunit', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + # GDMLShared.setTrace(True) + GDMLShared.trace("Execute Hyperbolic Tube") + # this should probably be a global variable, but + # for now adopt the value used in geant4.10.07.p02 + NUMBER_OF_DIVISIONS = 36 + mul = GDMLShared.getMult(fp) + rmin = mul * fp.rmin + rmax = mul * fp.rmax + z = mul * fp.z + inst = getAngleRad(fp.aunit, fp.inst) + outst = getAngleRad(fp.aunit, fp.outst) + sqrtan1 = math.tan(inst) + sqrtan1 *= sqrtan1 + sqrtan2 = math.tan(outst) + sqrtan2 *= sqrtan2 + + # mirroring error checking in HepPolyhedron.cc + k = 0 + if rmin < 0. or rmax < 0. or rmin >= rmax: + k = 1 + if z <= 0.: + k += 2 + + if k != 0: + errmsg = "HepPolyhedronHype: error in input parameters: " + if (k & 1) != 0: + errmsg += " (radii)" + if (k & 2) != 0: + errmsg += " (half-length)" + print(errmsg) + print(f' rmin= {rmin} rmax= {rmax} z= {z}') + return + + # Prepare two polylines + ns = NUMBER_OF_DIVISIONS + if ns < 3: + ns = 3 + if sqrtan1 == 0.: + nz1 = 2 + else: + nz1 = ns + 1 + if sqrtan2 == 0.: + nz2 = 2 + else: + nz2 = ns + 1 + + halfZ = z/2 + # + # solid generated by external hyperbeloid + dz2 = z/(nz2 - 1) + zz = [halfZ - dz2*i for i in range(0, nz2)] + rr = [math.sqrt(sqrtan2*zi*zi + rmax*rmax) for zi in zz] + outersolid = rotateAroundZ(NUMBER_OF_DIVISIONS, zz, rr) + fp.Shape = outersolid + + if rmin != 0: + # + # solid generated by internal hyperbeloid + dz1 = z/(nz1 - 1) + zz = [halfZ - dz1*i for i in range(0, nz1)] + rr = [math.sqrt(sqrtan1*zi*zi + rmin*rmin) for zi in zz] + innersolid = rotateAroundZ(NUMBER_OF_DIVISIONS, zz, rr) + fp.Shape = outersolid.cut(innersolid) + + fp.Placement = currPlacement + + +class GDMLParaboloid(GDMLsolid): + def __init__(self, obj, rlo, rhi, dz, lunit, + material, colour=None): + super().__init__(obj) + '''Add some custom properties for the Paraboloid feature''' + obj.addProperty("App::PropertyFloat", "rlo", "GDMLParaboloid", + "radius at -z/2").rlo = rlo + obj.addProperty("App::PropertyFloat", "rhi", "GDMLParaboloid", + "radius at +z/2").rhi = rhi + obj.addProperty("App::PropertyFloat", "dz", "GDMLParaboloid", + "Paraboloid half length").dz = dz + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLParaboloid", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLParaboloid", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLParaboloid' + self.colour = colour + self.Object = obj + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['rlo', 'rhi', 'z', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + # GDMLShared.setTrace(True) + GDMLShared.trace("Execute Hyperbolic Tube") + # this should probably be a global variable, but + # for now adopt the value used in geant4.10.07.p02 + NUMBER_OF_DIVISIONS = 24 + mul = GDMLShared.getMult(fp) + rlo = mul * fp.rlo + rhi = mul * fp.rhi + dz = mul * fp.dz + if dz < 0 or rlo > rhi: + errmsg = "paraboloid: error in input parameters: dz < 0 and/or rlo > rhi" + print(errmsg) + print(f' rlo= {rlo} rhi= {rhi} dz= {dz}') + return + + # Prepare polylines + ns = NUMBER_OF_DIVISIONS + # paraboloid given by following equation: + # rho^2 = k1 * z + k2, (rho = distance of point on surface from z-axis) + # k1 and k2 can be obtained from requirement: + # rlo^2 = k1*(-dz) + k2 + # rhi^2 = k1*(dz) + k2 + k1 = (rhi*rhi - rlo*rlo)/(2*dz) + k2 = (rhi*rhi + rlo*rlo)/2 + # + # solid generated by external hyperbeloid + deltaz = 2*dz/(ns - 1) + zz = [dz - deltaz*i for i in range(0, ns)] + rr = [math.sqrt(k1*zi+k2) for zi in zz] + outersolid = rotateAroundZ(NUMBER_OF_DIVISIONS, zz, rr) + fp.Shape = outersolid + + fp.Placement = currPlacement + + +class GDMLPolyhedra(GDMLsolid): + def __init__(self, obj, startphi, deltaphi, numsides, aunit, lunit, + material, colour=None): + super().__init__(obj) + '''Add some custom properties for Polyhedra feature''' + obj.addProperty("App::PropertyFloat", "startphi", "GDMLPolyhedra", + "Start Angle").startphi = startphi + obj.addProperty("App::PropertyFloat", "deltaphi", "GDMLPolyhedra", + "Delta Angle").deltaphi = deltaphi + obj.addProperty("App::PropertyInteger", "numsides", "GDMLPolyhedra", + "Number of Side").numsides = numsides + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLPolyhedra", + "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLPolyhdera", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLPolyhedra", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLPolyhedra' + self.colour = colour + self.Object = obj + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['startphi', 'deltaphi', 'numsides', 'aunit', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + # GDMLShared.setTrace(True) + GDMLShared.trace("Execute Polyhedra") + parms = fp.OutList + GDMLShared.trace("Number of parms : " + str(len(parms))) + numsides = fp.numsides + GDMLShared.trace("Number of sides : " + str(numsides)) + mul = GDMLShared.getMult(fp) + z0 = parms[0].z * mul + rmin0 = parms[0].rmin * mul + rmax0 = parms[0].rmax * mul + GDMLShared.trace("Top z : " + str(z0)) + GDMLShared.trace("Top rmin : " + str(rmin0)) + GDMLShared.trace("Top rmax : " + str(rmax0)) + inner_faces = [] + outer_faces = [] + numsides = int(numsides * 360 / getAngleDeg(fp.aunit, fp.deltaphi)) + # Deal with Inner Top Face + # Could be point rmin0 = rmax0 = 0 + if rmin0 > 0: + inner_poly0 = makeRegularPolygon(numsides, rmin0, z0) + inner_faces.append(Part.Face(Part.makePolygon(inner_poly0))) + # Deal with Outer Top Face + outer_poly0 = makeRegularPolygon(numsides, rmax0, z0) + if rmax0 > 0: # Only make polygon if not a point outer_faces.append(Part.Face(Part.makePolygon(outer_poly0))) - for ptr in parms[1:] : - z1 = ptr.z * mul - rmin1 = ptr.rmin * mul - rmax1 = ptr.rmax * mul - GDMLShared.trace("z1 : "+str(z1)) - GDMLShared.trace("rmin1 : "+str(rmin1)) - GDMLShared.trace("rmax1 : "+str(rmax1)) - # Concat face lists - if rmin0 > 0 : - inner_poly1 = makeRegularPolygon(numsides,rmin1,z1) - inner_faces = inner_faces + \ - makeFrustrum(numsides,inner_poly0,inner_poly1) - inner_poly0 = inner_poly1 - inner_faces.append(Part.Face(Part.makePolygon(inner_poly1))) - # Deal with Outer - outer_poly1 = makeRegularPolygon(numsides,rmax1,z1) - outer_faces = outer_faces + \ - makeFrustrum(numsides,outer_poly0,outer_poly1) - # update for next zsection - outer_poly0 = outer_poly1 - z0 = z1 - # add bottom polygon face - outer_faces.append(Part.Face(Part.makePolygon(outer_poly1))) - GDMLShared.trace("Total Faces : "+str(len(inner_faces))) - outer_shell = Part.makeShell(outer_faces) - outer_solid = Part.makeSolid(outer_shell) - if rmin0 > 0 : - inner_shell = Part.makeShell(inner_faces) - inner_solid = Part.makeSolid(inner_shell) - shape = outer_solid.cut(inner_solid) - else : - shape = outer_solid - #fp.Shape = shell - if checkFullCircle(fp.aunit,fp.deltaphi) == False : - newShape = angleSectionSolid(fp, rmax1, z0, shape) - fp.Shape = newShape - else : - fp.Shape = shape - fp.Placement = currPlacement - -class GDMLGenericPolyhedra(GDMLsolid) : - def __init__(self, obj, startphi, deltaphi, numsides, aunit, lunit, \ - material, colour = None) : - super().__init__(obj) - '''Add some custom properties for Generic Polyhedra feature''' - obj.addProperty("App::PropertyFloat","startphi","GDMLGenericPolyhedra", \ - "Start Angle").startphi=startphi - obj.addProperty("App::PropertyFloat","deltaphi","GDMLGenericPolyhedra", \ - "Delta Angle").deltaphi=deltaphi - obj.addProperty("App::PropertyInteger","numsides","GDMLGenericPolyhedra", \ - "Number of Side").numsides=numsides - obj.addProperty("App::PropertyEnumeration","aunit","GDMLGenericPolyhedra", \ - "aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLGenericPolyhdera","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLGenericPolyhedra", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLGenericPolyhedra' - self.colour = colour - self.Object = obj - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['startphi', 'deltaphi', 'numsides', 'aunit','lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - #GDMLShared.setTrace(True) - GDMLShared.trace("Execute GenericPolyhedra") - rzpoints = fp.OutList - if len(rzpoints) < 3: - print("Error in genericPolyhedra: number of rzpoints less than 3") - return - GDMLShared.trace("Number of rzpoints : "+str(len(rzpoints))) - numsides = fp.numsides - GDMLShared.trace("Number of sides : "+str(numsides)) - mul = GDMLShared.getMult(fp) - faces = [] - startphi = getAngleRad(fp.aunit, fp.startphi) - dphi = getAngleRad(fp.aunit, fp.deltaphi)/numsides - # form vertexes - verts = [] - for ptr in rzpoints: - z = ptr.z * mul - r = ptr.r * mul - phi = startphi - for i in range(0,numsides+1): - v = FreeCAD.Vector(r*math.cos(phi), r*math.sin(phi), z) - verts.append(v) - phi += dphi - - numverts = len(verts) - stride = numsides + 1 - #outer faces - for k0 in range(0, numverts-stride, stride): - for i in range(0, numsides): - k = k0 + i - wire = Part.makePolygon([verts[k], verts[k+stride], \ - verts[k+stride+1], verts[k+1], \ - verts[k]]) - faces.append(Part.Face(wire)) - - #inner faces - for i in range(0, numsides): - k = numverts - stride + i - wire = Part.makePolygon([verts[i], verts[k], \ - verts[k+1], verts[i+1], \ - verts[i]]) - faces.append(Part.Face(wire)) - - #side faces - if checkFullCircle(fp.aunit, fp.deltaphi) == False: - verts1 = [verts[k] for k in range(0, numverts - stride + 1, stride)] - verts1.append(verts1[0]) - wire = Part.makePolygon(verts1) - faces.append(Part.Face(wire)) - verts1 = [verts[k] for k in range(numsides, numverts, stride)] - verts1.append(verts1[0]) - wire = Part.makePolygon(verts1) - faces.append(Part.Face(wire)) - - shell = Part.makeShell(faces) - solid = Part.makeSolid(shell) - fp.Shape = solid - fp.Placement = currPlacement - -class GDMLTorus(GDMLsolid) : - def __init__(self, obj, rmin, rmax, rtor, startphi, deltaphi, \ - aunit, lunit, material, colour = None) : - super().__init__(obj) - obj.addProperty("App::PropertyFloat","rmin","GDMLTorus", \ - "rmin").rmin=rmin - obj.addProperty("App::PropertyFloat","rmax","GDMLTorus", \ - "rmax").rmax=rmax - obj.addProperty("App::PropertyFloat","rtor","GDMLTorus", \ - "rtor").rtor=rtor - obj.addProperty("App::PropertyFloat","startphi","GDMLTorus", \ - "startphi").startphi=startphi - obj.addProperty("App::PropertyFloat","deltaphi","GDMLTorus", \ - "deltaphi").deltaphi=deltaphi - obj.addProperty("App::PropertyString","aunit","GDMLTorus", \ - "aunit").aunit=aunit - obj.addProperty("App::PropertyEnumeration","lunit","GDMLTorus","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLTorus", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLTorus' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['rmin', 'rmax', 'rtor','startphi','deltaphi', \ - 'aunit','lunit'] : - #print(f'Change Prop : {prop}') - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - GDMLShared.trace("Create Torus") - mul = GDMLShared.getMult(fp) - rmin = mul*fp.rmin - rmax = mul*fp.rmax - rtor = mul*fp.rtor - - spnt = FreeCAD.Vector(0,0,0) - sdir = FreeCAD.Vector(0,0,1) - - outerTorus = Part.makeTorus(rtor,rmax,spnt,sdir,0,360, \ - getAngleDeg(fp.aunit, fp.deltaphi)) - if rmin > 0 : - innerTorus = Part.makeTorus(rtor,rmin,spnt,sdir,0,360, \ - getAngleDeg(fp.aunit, fp.deltaphi)) - torus = outerTorus.cut(innerTorus) - else : - torus = outerTorus - if fp.startphi != 0 : - torus.rotate(spnt,sdir,getAngleDeg(fp.aunit,fp.startphi)) - fp.Shape = torus - fp.Placement = currPlacement - -class GDMLTwistedbox(GDMLsolid) : - def __init__(self, obj, PhiTwist, x, y, z, aunit, lunit, material, colour=None): - super().__init__(obj) - '''Add some custom properties to our Box feature''' - GDMLShared.trace("GDMLTwistedbox init") - #GDMLShared.trace("material : "+material) - obj.addProperty("App::PropertyFloat","x","GDMLTwistedbox","Length x").x=x - obj.addProperty("App::PropertyFloat","y","GDMLTwistedbox","Length y").y=y - obj.addProperty("App::PropertyFloat","z","GDMLTwistedbox","Length z").z=z - angle = getAngleDeg(aunit, PhiTwist) - if angle > 90: - print(f'PhiTwist angle cannot be larger than 90 deg') - angle = 90 - aunit = "deg" - elif angle < -90: - print(f'PhiTwist angle cannot be less than -90 deg') - angle = -90 - aunit = "deg" - else: - angle = PhiTwist - - obj.addProperty("App::PropertyFloat","PhiTwist","GDMLTwistedbox","Twist Angle").PhiTwist=angle - obj.addProperty("App::PropertyEnumeration","aunit","GDMLTwistedbox","aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLTwistedbox","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLTwistedbox","Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLTwistedbox' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - # Changing Shape in createGeometry will redrive onChanged - if ('Restore' in fp.State) : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['x','y','z','PhiTwist', 'lunit', 'aunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - #print('createGeometry') - #print(fp) - - if all((fp.x,fp.y,fp.z, fp.PhiTwist)) : - currPlacement = fp.Placement - - #if (hasattr(fp,'x') and hasattr(fp,'y') and hasattr(fp,'z')) : - mul = GDMLShared.getMult(fp) - GDMLShared.trace('mul : '+str(mul)) - x = mul * fp.x - y = mul * fp.y - z = mul * fp.z - angle = getAngleDeg(fp.aunit,fp.PhiTwist) - # lower rectanngle vertexes - v1 = FreeCAD.Vector(-x/2, -y/2, -z/2) - v2 = FreeCAD.Vector( x/2, -y/2, -z/2) - v3 = FreeCAD.Vector( x/2, y/2, -z/2) - v4 = FreeCAD.Vector(-x/2, y/2, -z/2) - pbot = Part.makePolygon([v1,v2,v3,v4,v1]) - slices = [] - N = 5 - dz = z/(N-1) - dPhi = angle/(N-1) - for i in range(0,N): - p = pbot.translated(FreeCAD.Vector(0,0,i*dz)) - p.rotate(FreeCAD.Vector(0,0,0), FreeCAD.Vector(0,0,1), -angle/2 + i*dPhi) - slices.append(p) - loft = Part.makeLoft(slices, True, False) - - fp.Shape = loft - fp.Placement = currPlacement - - def OnDocumentRestored(self,obj) : - print('Doc Restored') - - -class GDMLTwistedtrap(GDMLsolid) : - def __init__(self, obj, PhiTwist, z, theta, phi, x1, x2, x3, x4, y1, y2, alpha, \ - aunit, lunit, material, colour = None): - super().__init__(obj) - '''General Trapezoid''' - obj.addProperty("App::PropertyFloat","PhiTwist","GDMLTwistedtrap","Twist angle").PhiTwist=PhiTwist - obj.addProperty("App::PropertyFloat","z","GDMLTwistedtrap","z").z=z - obj.addProperty("App::PropertyFloat","Theta","GDMLTwistedtrap","Theta"). \ - Theta=theta - obj.addProperty("App::PropertyFloat","Phi","GDMLTwistedtrap","Phi").Phi=phi - obj.addProperty("App::PropertyFloat","x1","GDMLTwistedtrap", \ - "Length x at y= -y1/2 of face at -z/2").x1=x1 - obj.addProperty("App::PropertyFloat","x2","GDMLTwistedtrap", \ - "Length x at y= +y1/2 of face at -z/2").x2=x2 - obj.addProperty("App::PropertyFloat","x3","GDMLTwistedtrap", \ - "Length x at y= -y2/2 of face at +z/2").x3=x3 - obj.addProperty("App::PropertyFloat","x4","GDMLTwistedtrap", \ - "Length x at y= +y2/2 of face at +z/2").x4=x4 - obj.addProperty("App::PropertyFloat","y1","GDMLTwistedtrap", \ - "Length y at face -z/2").y1=y1 - obj.addProperty("App::PropertyFloat","y2","GDMLTwistedtrap", \ - "Length y at face +z/2").y2=y2 - obj.addProperty("App::PropertyFloat","Alph","GDMLTwistedtrap","Alph"). \ - Alph=alpha - obj.addProperty("App::PropertyEnumeration","aunit","GDMLTwistedtrap","aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLTwistedtrap","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLTwistedtrap","Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - obj.Proxy = self - self.Type = 'GDMLTwistedtrap' - self.colour = colour - - def onChanged(self, fp, prop): - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['PhiTwist', 'z','theta','phi','x1','x2','x3','x4','y1','y2','alpha', \ - 'aunit', 'lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - # Define six vetices for the shape - alpha = getAngleRad(fp.aunit,fp.Alph) - theta = getAngleRad(fp.aunit,fp.Theta) - phi = getAngleRad(fp.aunit,fp.Phi) - PhiTwist = getAngleDeg(fp.aunit,fp.PhiTwist) - mul = GDMLShared.getMult(fp) - y1 = mul * fp.y1 - x1 = mul * fp.x1 - x2 = mul * fp.x2 - y2 = mul * fp.y2 - x3 = mul * fp.x3 - x4 = mul * fp.x4 - z = mul * fp.z - - N = 9 - dz = z/(N-1) - dTwist = PhiTwist/(N-1) - - tanalpha = math.tan(alpha) - dx1 = y1*math.tan(alpha) - dx2 = y2*math.tan(alpha) - - dt = 1.0/(N-1) - t = 0 - slices = [] - tanthet = math.tan(theta) - cosphi = math.cos(phi) - sinphi = math.sin(phi) - rhomax = z*tanthet - xoffset = -rhomax*cosphi/2 - yoffset = -rhomax*sinphi/2 - for i in range(0,N): - #Vertexes, counter clock wise order - y = y1 + t*(y2-y1) # go continuously from y1 to y2 - dx = y*tanalpha - x13 = x1 + t*(x3-x1) # go continuously from x1 to x3 - x24 = x2 + t*(x4-x2) # go continuously from x1 to x3 - zt = -z/2 +t*z - rho = i*dz*tanthet - dxphi = xoffset + rho*cosphi - dyphi = yoffset + rho*sinphi - v1 = FreeCAD.Vector(-x13/2 - dx/2 + dxphi, -y/2 + dyphi, zt) - v2 = FreeCAD.Vector( x13/2 - dx/2 + dxphi, -y/2 + dyphi, zt) - v3 = FreeCAD.Vector( x24/2 + dx/2 + dxphi, y/2 + dyphi, zt) - v4 = FreeCAD.Vector(-x24/2 + dx/2 + dxphi, y/2 + dyphi, zt) - p = Part.makePolygon([v1,v2,v3,v4,v1]) - p.rotate(FreeCAD.Vector(0,0,0), FreeCAD.Vector(0,0,1), -PhiTwist/2 + i*dTwist) - slices.append(p) - t += dt - - loft = Part.makeLoft(slices, True, False) - fp.Shape = loft - fp.Placement = currPlacement - - -class GDMLTwistedtrd(GDMLsolid) : - def __init__(self, obj, PhiTwist, z, x1, x2, y1, y2, aunit, lunit, material, colour = None) : - super().__init__(obj) - "3.4.15 : Trapezoid – x & y varying along z" - obj.addProperty("App::PropertyFloat","z","GDMLTwistedtrd`","z").z=z - obj.addProperty("App::PropertyFloat","x1","GDMLTwistedtrd", \ - "Length x at face -z/2").x1=x1 - obj.addProperty("App::PropertyFloat","x2","GDMLTwistedtrd", \ - "Length x at face +z/2").x2=x2 - obj.addProperty("App::PropertyFloat","y1","GDMLTwistedtrd", \ - "Length y at face -z/2").y1=y1 - obj.addProperty("App::PropertyFloat","y2","GDMLTwistedtrd", \ - "Length y at face +z/2").y2=y2 - obj.addProperty("App::PropertyEnumeration","lunit","GDMLTwistedtrd","lunit") - angle = getAngleDeg(aunit, PhiTwist) - if angle > 90: - print(f'PhiTwist angle cannot be larger than 90 deg') - angle = 90 - aunit = "deg" - elif angle < -90: - print(f'PhiTwist angle cannot be less than -90 deg') - angle = -90 - aunit = "deg" - else: - angle = PhiTwist - - obj.addProperty("App::PropertyFloat","PhiTwist","GDMLTwistedtrd","Twist Angle").PhiTwist=angle - obj.addProperty("App::PropertyEnumeration","aunit","GDMLTwistedtrd","aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLTwistedtrd","Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLTwistedtrd' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - # Changing Shape in createGeometry will redrive onChanged - if ('Restore' in fp.State) : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['x1', 'y1', 'x2', 'y2', 'z','PhiTwist', 'lunit', 'aunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - #print('createGeometry') - #print(fp) - - if all((fp.x1, fp.x2, fp.y1, fp.y2, fp.z, fp.PhiTwist)) : - currPlacement = fp.Placement - - #if (hasattr(fp,'x') and hasattr(fp,'y') and hasattr(fp,'z')) : - mul = GDMLShared.getMult(fp) - x1 = (fp.x1 * mul) - x2 = (fp.x2 * mul) - y1 = (fp.y1 * mul) - y2 = (fp.y2 * mul) - z = (fp.z * mul) - GDMLShared.trace('mul : '+str(mul)) - angle = getAngleDeg(fp.aunit,fp.PhiTwist) - slices = [] - N = 9 #number of slices - dz = z/(N-1) - dPhi = angle/(N-1) - for i in range(0,N): - t = i*1./(N-1) - xside = x1 + t*(x2 - x1) - yside = y1 + t*(y2 - y1) - v1 = FreeCAD.Vector(-xside/2, -yside/2, -z/2 + i*dz) - v2 = FreeCAD.Vector( xside/2, -yside/2, -z/2 + i*dz) - v3 = FreeCAD.Vector( xside/2, yside/2, -z/2 + i*dz) - v4 = FreeCAD.Vector(-xside/2, yside/2, -z/2 + i*dz) - p = Part.makePolygon([v1,v2,v3,v4,v1]) - p.rotate(FreeCAD.Vector(0,0,0), FreeCAD.Vector(0,0,1), -angle/2 + i*dPhi) - slices.append(p) - - loft = Part.makeLoft(slices, True, False) - fp.Shape = loft - fp.Placement = currPlacement - - def OnDocumentRestored(self,obj) : - print('Doc Restored') - - -class GDMLTwistedtubs(GDMLsolid) : - def __init__(self, obj,endinnerrad,endouterrad,zlen,twistedangle,phi,aunit,lunit,material, colour = None) : - super().__init__(obj) - '''Twisted tube''' - obj.addProperty("App::PropertyFloat","zlen","GDMLTwistedtubs","zlen").zlen=zlen - obj.addProperty("App::PropertyFloat","endinnerrad","GDMLTwistedtubs", \ - "Inside radius at caps").endinnerrad=endinnerrad - obj.addProperty("App::PropertyFloat","endouterrad","GDMLTwistedtubs", \ - "Outside radius at caps").endouterrad=endouterrad - obj.addProperty("App::PropertyEnumeration","lunit","GDMLTwistedtubs","lunit") - angle = getAngleDeg(aunit, twistedangle) - if angle > 90: - print(f'PhiTwist angle cannot be larger than 90 deg') - angle = 90 - aunit = "deg" - elif angle < -90: - print(f'PhiTwist angle cannot be less than -90 deg') - angle = -90 - aunit = "deg" - else: - angle = twistedangle - - obj.addProperty("App::PropertyFloat","twistedangle","GDMLTwistedtubs","Twist Angle").twistedangle=angle - obj.addProperty("App::PropertyFloat","phi","GDMLTwistedtubs","Delta phi").phi=phi - obj.addProperty("App::PropertyEnumeration","aunit","GDMLTwistedtubs","aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLTwistedtubs","Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLTwistedtubs' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - # Changing Shape in createGeometry will redrive onChanged - if ('Restore' in fp.State) : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['endinnerrad', 'endouterrad', 'zlen', 'twistedangle', 'phi', 'lunit', 'aunit'] : - self.createGeometry(fp) + for ptr in parms[1:]: + z1 = ptr.z * mul + rmin1 = ptr.rmin * mul + rmax1 = ptr.rmax * mul + GDMLShared.trace("z1 : "+str(z1)) + GDMLShared.trace("rmin1 : "+str(rmin1)) + GDMLShared.trace("rmax1 : "+str(rmax1)) + # Concat face lists + if rmin0 > 0: + inner_poly1 = makeRegularPolygon(numsides, rmin1, z1) + inner_faces = inner_faces + \ + makeFrustrum(numsides, inner_poly0, inner_poly1) + inner_poly0 = inner_poly1 + inner_faces.append(Part.Face(Part.makePolygon(inner_poly1))) + # Deal with Outer + outer_poly1 = makeRegularPolygon(numsides, rmax1, z1) + outer_faces = outer_faces + \ + makeFrustrum(numsides, outer_poly0, outer_poly1) + # update for next zsection + outer_poly0 = outer_poly1 + z0 = z1 + # add bottom polygon face + outer_faces.append(Part.Face(Part.makePolygon(outer_poly1))) + GDMLShared.trace("Total Faces : " + str(len(inner_faces))) + outer_shell = Part.makeShell(outer_faces) + outer_solid = Part.makeSolid(outer_shell) + if rmin0 > 0: + inner_shell = Part.makeShell(inner_faces) + inner_solid = Part.makeSolid(inner_shell) + shape = outer_solid.cut(inner_solid) + else: + shape = outer_solid + # fp.Shape = shell + if checkFullCircle(fp.aunit, fp.deltaphi) is False: + newShape = angleSectionSolid(fp, rmax1, z0, shape) + fp.Shape = newShape + else: + fp.Shape = shape + fp.Placement = currPlacement - #def execute(self, fp): in GDMLsolid - def createGeometry(self,fp): - #print('createGeometry') - #print(fp) +class GDMLGenericPolyhedra(GDMLsolid): + def __init__(self, obj, startphi, deltaphi, numsides, aunit, lunit, + material, colour=None): + super().__init__(obj) + '''Add some custom properties for Generic Polyhedra feature''' + obj.addProperty("App::PropertyFloat", "startphi", "GDMLGenericPolyhedra", + "Start Angle").startphi = startphi + obj.addProperty("App::PropertyFloat", "deltaphi", "GDMLGenericPolyhedra", + "Delta Angle").deltaphi = deltaphi + obj.addProperty("App::PropertyInteger", "numsides", "GDMLGenericPolyhedra", + "Number of Side").numsides = numsides + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLGenericPolyhedra", + "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLGenericPolyhdera", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLGenericPolyhedra", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLGenericPolyhedra' + self.colour = colour + self.Object = obj + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return - if all((fp.endouterrad, fp.zlen, fp.phi)) : - currPlacement = fp.Placement - - mul = GDMLShared.getMult(fp) - rin = (fp.endinnerrad * mul) - rout = (fp.endouterrad * mul) - if rin > rout: - print(f'Erro: Inner radius ({rin}) greater than outer radius ({rout})') - return - zlen = (fp.zlen * mul) - GDMLShared.trace('mul : '+str(mul)) - angle = getAngleDeg(fp.aunit,fp.twistedangle) - phi = getAngleRad(fp.aunit,fp.phi) - phideg = getAngleDeg(fp.aunit,fp.phi) - slices = [] - N = 9 #number of slices - dz = zlen/(N-1) - dtwist = angle/(N-1) - #construct base wire - # Vertexes - v1 = FreeCAD.Vector(rin, 0, 0) - v2 = FreeCAD.Vector(rout,0, 0) - v3 = FreeCAD.Vector(rout*math.cos(phi), rout*math.sin(phi), 0) - v4 = FreeCAD.Vector(rin*math.cos(phi), rin*math.sin(phi), 0) - #arc center points - vCin = FreeCAD.Vector(rin*math.cos(phi/2), rin*math.sin(phi/2), 0) - vCout = FreeCAD.Vector(rout*math.cos(phi/2), rout*math.sin(phi/2), 0) - # Center of twisting - rc = (rin + rout)/2 - vc = FreeCAD.Vector(rc*math.cos(phi/2), rc*math.sin(phi/2), 0) - # wire - arcin = Part.Arc(v1, vCin, v4) - line1 = Part.LineSegment(v4, v3) - arcout = Part.Arc(v3, vCout, v2) - line2 = Part.LineSegment(v2, v1) - - s = Part.Shape([arcin, line1, arcout, line2]) - w = Part.Wire(s.Edges) - angoffset = -angle/2 -phideg/2 - - for i in range(0,N): - p = w.translated(FreeCAD.Vector(0, 0, -zlen/2 + i*dz)) - p.rotate(vc, FreeCAD.Vector(0,0,1), angoffset + i*dtwist) - slices.append(p) - - loft = Part.makeLoft(slices, True, False) - fp.Shape = loft - fp.Placement = currPlacement - - def OnDocumentRestored(self,obj) : - print('Doc Restored') - - -class GDMLXtru(GDMLsolid) : - def __init__(self, obj, lunit, material, colour = None) : - super().__init__(obj) - obj.addExtension('App::GroupExtensionPython') - obj.addProperty("App::PropertyEnumeration","lunit","GDMLXtru","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLXtru", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLXtru' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['startphi','deltaphi','aunit','lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['startphi', 'deltaphi', 'numsides', 'aunit', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + # GDMLShared.setTrace(True) + GDMLShared.trace("Execute GenericPolyhedra") + rzpoints = fp.OutList + if len(rzpoints) < 3: + print("Error in genericPolyhedra: number of rzpoints less than 3") + return + GDMLShared.trace("Number of rzpoints : " + str(len(rzpoints))) + numsides = fp.numsides + GDMLShared.trace("Number of sides : " + str(numsides)) + mul = GDMLShared.getMult(fp) + faces = [] + startphi = getAngleRad(fp.aunit, fp.startphi) + dphi = getAngleRad(fp.aunit, fp.deltaphi)/numsides + # form vertexes + verts = [] + for ptr in rzpoints: + z = ptr.z * mul + r = ptr.r * mul + phi = startphi + for i in range(0, numsides+1): + v = FreeCAD.Vector(r*math.cos(phi), r*math.sin(phi), z) + verts.append(v) + phi += dphi + + numverts = len(verts) + stride = numsides + 1 + # outer faces + for k0 in range(0, numverts-stride, stride): + for i in range(0, numsides): + k = k0 + i + wire = Part.makePolygon([verts[k], verts[k+stride], + verts[k+stride+1], verts[k+1], + verts[k]]) + faces.append(Part.Face(wire)) + + # inner faces + for i in range(0, numsides): + k = numverts - stride + i + wire = Part.makePolygon([verts[i], verts[k], + verts[k+1], verts[i+1], + verts[i]]) + faces.append(Part.Face(wire)) + + # side faces + if checkFullCircle(fp.aunit, fp.deltaphi) is False: + verts1 = [verts[k] for k in range(0, numverts - stride + 1, stride)] + verts1.append(verts1[0]) + wire = Part.makePolygon(verts1) + faces.append(Part.Face(wire)) + verts1 = [verts[k] for k in range(numsides, numverts, stride)] + verts1.append(verts1[0]) + wire = Part.makePolygon(verts1) + faces.append(Part.Face(wire)) + + shell = Part.makeShell(faces) + solid = Part.makeSolid(shell) + fp.Shape = solid + fp.Placement = currPlacement + + +class GDMLTorus(GDMLsolid): + def __init__(self, obj, rmin, rmax, rtor, startphi, deltaphi, + aunit, lunit, material, colour=None): + super().__init__(obj) + obj.addProperty("App::PropertyFloat", "rmin", "GDMLTorus", + "rmin").rmin = rmin + obj.addProperty("App::PropertyFloat", "rmax", "GDMLTorus", + "rmax").rmax = rmax + obj.addProperty("App::PropertyFloat", "rtor", "GDMLTorus", + "rtor").rtor = rtor + obj.addProperty("App::PropertyFloat", "startphi", "GDMLTorus", + "startphi").startphi = startphi + obj.addProperty("App::PropertyFloat", "deltaphi", "GDMLTorus", + "deltaphi").deltaphi = deltaphi + obj.addProperty("App::PropertyString", "aunit", "GDMLTorus", + "aunit").aunit = aunit + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLTorus", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLTorus", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLTorus' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['rmin', 'rmax', 'rtor', 'startphi', 'deltaphi', + 'aunit', 'lunit']: + # print(f'Change Prop : {prop}') + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + GDMLShared.trace("Create Torus") + mul = GDMLShared.getMult(fp) + rmin = mul*fp.rmin + rmax = mul*fp.rmax + rtor = mul*fp.rtor + + spnt = FreeCAD.Vector(0, 0, 0) + sdir = FreeCAD.Vector(0, 0, 1) + + outerTorus = Part.makeTorus(rtor, rmax, spnt, sdir, 0, 360, + getAngleDeg(fp.aunit, fp.deltaphi)) + if rmin > 0: + innerTorus = Part.makeTorus(rtor, rmin, spnt, sdir, 0, 360, + getAngleDeg(fp.aunit, fp.deltaphi)) + torus = outerTorus.cut(innerTorus) + else: + torus = outerTorus + if fp.startphi != 0: + torus.rotate(spnt, sdir, getAngleDeg(fp.aunit, fp.startphi)) + fp.Shape = torus + fp.Placement = currPlacement + + +class GDMLTwistedbox(GDMLsolid): + def __init__(self, obj, PhiTwist, x, y, z, aunit, lunit, material, + colour=None): + super().__init__(obj) + '''Add some custom properties to our Box feature''' + GDMLShared.trace("GDMLTwistedbox init") + # GDMLShared.trace("material : "+material) + obj.addProperty("App::PropertyFloat", "x", "GDMLTwistedbox", + "Length x").x = x + obj.addProperty("App::PropertyFloat", "y", "GDMLTwistedbox", + "Length y").y = y + obj.addProperty("App::PropertyFloat", "z", "GDMLTwistedbox", + "Length z").z = z + angle = getAngleDeg(aunit, PhiTwist) + if angle > 90: + print(f'PhiTwist angle cannot be larger than 90 deg') + angle = 90 + aunit = "deg" + elif angle < -90: + print(f'PhiTwist angle cannot be less than -90 deg') + angle = -90 + aunit = "deg" + else: + angle = PhiTwist + + obj.addProperty("App::PropertyFloat", "PhiTwist", "GDMLTwistedbox", + "Twist Angle").PhiTwist = angle + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLTwistedbox", + "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLTwistedbox", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLTwistedbox", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLTwistedbox' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + # Changing Shape in createGeometry will redrive onChanged + if ('Restore' in fp.State): + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['x', 'y', 'z', 'PhiTwist', 'lunit', 'aunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + # print('createGeometry') + # print(fp) + + if all((fp.x, fp.y, fp.z, fp.PhiTwist)): + currPlacement = fp.Placement + + # if (hasattr(fp,'x') and hasattr(fp,'y') and hasattr(fp,'z')) : + mul = GDMLShared.getMult(fp) + GDMLShared.trace('mul : '+str(mul)) + x = mul * fp.x + y = mul * fp.y + z = mul * fp.z + angle = getAngleDeg(fp.aunit, fp.PhiTwist) + # lower rectanngle vertexes + v1 = FreeCAD.Vector(-x/2, -y/2, -z/2) + v2 = FreeCAD.Vector(x/2, -y/2, -z/2) + v3 = FreeCAD.Vector(x/2, y/2, -z/2) + v4 = FreeCAD.Vector(-x/2, y/2, -z/2) + pbot = Part.makePolygon([v1, v2, v3, v4, v1]) + slices = [] + N = 5 + dz = z/(N-1) + dPhi = angle/(N-1) + for i in range(0, N): + p = pbot.translated(FreeCAD.Vector(0, 0, i*dz)) + p.rotate(FreeCAD.Vector(0, 0, 0), + FreeCAD.Vector(0, 0, 1), -angle/2 + i*dPhi) + slices.append(p) + loft = Part.makeLoft(slices, True, False) + + fp.Shape = loft + fp.Placement = currPlacement + + def OnDocumentRestored(self, obj): + print('Doc Restored') + + +class GDMLTwistedtrap(GDMLsolid): + def __init__(self, obj, PhiTwist, z, theta, phi, x1, x2, x3, x4, y1, y2, + alpha, aunit, lunit, material, colour=None): + super().__init__(obj) + '''General Trapezoid''' + obj.addProperty("App::PropertyFloat", "PhiTwist", "GDMLTwistedtrap", + "Twist angle").PhiTwist = PhiTwist + obj.addProperty("App::PropertyFloat", "z", "GDMLTwistedtrap", "z").z = z + obj.addProperty("App::PropertyFloat", "Theta", "GDMLTwistedtrap", + "Theta").Theta = theta + obj.addProperty("App::PropertyFloat", "Phi", "GDMLTwistedtrap", + "Phi").Phi = phi + obj.addProperty("App::PropertyFloat", "x1", "GDMLTwistedtrap", + "Length x at y= -y1/2 of face at -z/2").x1 = x1 + obj.addProperty("App::PropertyFloat", "x2", "GDMLTwistedtrap", + "Length x at y= +y1/2 of face at -z/2").x2 = x2 + obj.addProperty("App::PropertyFloat", "x3", "GDMLTwistedtrap", + "Length x at y= -y2/2 of face at +z/2").x3 = x3 + obj.addProperty("App::PropertyFloat", "x4", "GDMLTwistedtrap", + "Length x at y= +y2/2 of face at +z/2").x4 = x4 + obj.addProperty("App::PropertyFloat", "y1", "GDMLTwistedtrap", + "Length y at face -z/2").y1 = y1 + obj.addProperty("App::PropertyFloat", "y2", "GDMLTwistedtrap", + "Length y at face +z/2").y2 = y2 + obj.addProperty("App::PropertyFloat", "Alph", "GDMLTwistedtrap", + "Alph").Alph = alpha + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLTwistedtrap", + "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyEnumeration", "lunit", + "GDMLTwistedtrap", "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLTwistedtrap", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + obj.Proxy = self + self.Type = 'GDMLTwistedtrap' + self.colour = colour + + def onChanged(self, fp, prop): + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['PhiTwist', 'z', 'theta', 'phi', + 'x1', 'x2', 'x3', 'x4', 'y1', 'y2', 'alpha', + 'aunit', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + # Define six vetices for the shape + alpha = getAngleRad(fp.aunit, fp.Alph) + theta = getAngleRad(fp.aunit, fp.Theta) + phi = getAngleRad(fp.aunit, fp.Phi) + PhiTwist = getAngleDeg(fp.aunit, fp.PhiTwist) + mul = GDMLShared.getMult(fp) + y1 = mul * fp.y1 + x1 = mul * fp.x1 + x2 = mul * fp.x2 + y2 = mul * fp.y2 + x3 = mul * fp.x3 + x4 = mul * fp.x4 + z = mul * fp.z + + N = 9 + dz = z/(N-1) + dTwist = PhiTwist/(N-1) + + tanalpha = math.tan(alpha) + + dt = 1.0/(N-1) + t = 0 + slices = [] + tanthet = math.tan(theta) + cosphi = math.cos(phi) + sinphi = math.sin(phi) + rhomax = z*tanthet + xoffset = -rhomax*cosphi/2 + yoffset = -rhomax*sinphi/2 + for i in range(0, N): + # Vertexes, counter clock wise order + y = y1 + t*(y2-y1) # go continuously from y1 to y2 + dx = y*tanalpha + x13 = x1 + t*(x3-x1) # go continuously from x1 to x3 + x24 = x2 + t*(x4-x2) # go continuously from x1 to x3 + zt = -z/2 + t*z + rho = i*dz*tanthet + dxphi = xoffset + rho*cosphi + dyphi = yoffset + rho*sinphi + v1 = FreeCAD.Vector(-x13/2 - dx/2 + dxphi, -y/2 + dyphi, zt) + v2 = FreeCAD.Vector( x13/2 - dx/2 + dxphi, -y/2 + dyphi, zt) + v3 = FreeCAD.Vector( x24/2 + dx/2 + dxphi, y/2 + dyphi, zt) + v4 = FreeCAD.Vector(-x24/2 + dx/2 + dxphi, y/2 + dyphi, zt) + p = Part.makePolygon([v1, v2, v3, v4, v1]) + p.rotate(FreeCAD.Vector(0, 0, 0), + FreeCAD.Vector(0, 0, 1), -PhiTwist/2 + i*dTwist) + slices.append(p) + t += dt + + loft = Part.makeLoft(slices, True, False) + fp.Shape = loft + fp.Placement = currPlacement + + +class GDMLTwistedtrd(GDMLsolid): + def __init__(self, obj, PhiTwist, z, x1, x2, y1, y2, aunit, lunit, + material, colour=None): + super().__init__(obj) + "3.4.15 : Trapezoid – x & y varying along z" + obj.addProperty("App::PropertyFloat", "z", "GDMLTwistedtrd", "z").z = z + obj.addProperty("App::PropertyFloat", "x1", "GDMLTwistedtrd", + "Length x at face -z/2").x1 = x1 + obj.addProperty("App::PropertyFloat", "x2", "GDMLTwistedtrd", + "Length x at face +z/2").x2 = x2 + obj.addProperty("App::PropertyFloat", "y1", "GDMLTwistedtrd", + "Length y at face -z/2").y1 = y1 + obj.addProperty("App::PropertyFloat", "y2", "GDMLTwistedtrd", + "Length y at face +z/2").y2 = y2 + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLTwistedtrd", + "lunit") + angle = getAngleDeg(aunit, PhiTwist) + if angle > 90: + print(f'PhiTwist angle cannot be larger than 90 deg') + angle = 90 + aunit = "deg" + elif angle < -90: + print(f'PhiTwist angle cannot be less than -90 deg') + angle = -90 + aunit = "deg" + else: + angle = PhiTwist + + obj.addProperty("App::PropertyFloat", "PhiTwist", "GDMLTwistedtrd", + "Twist Angle").PhiTwist = angle + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLTwistedtrd", + "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", + "GDMLTwistedtrd", "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLTwistedtrd' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + # Changing Shape in createGeometry will redrive onChanged + if ('Restore' in fp.State): + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['x1', 'y1', 'x2', 'y2', 'z', 'PhiTwist', 'lunit', 'aunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + # print('createGeometry') + # print(fp) + + if all((fp.x1, fp.x2, fp.y1, fp.y2, fp.z, fp.PhiTwist)): + currPlacement = fp.Placement + + # if (hasattr(fp,'x') and hasattr(fp,'y') and hasattr(fp,'z')) : + mul = GDMLShared.getMult(fp) + x1 = (fp.x1 * mul) + x2 = (fp.x2 * mul) + y1 = (fp.y1 * mul) + y2 = (fp.y2 * mul) + z = (fp.z * mul) + GDMLShared.trace('mul : ' + str(mul)) + angle = getAngleDeg(fp.aunit, fp.PhiTwist) + slices = [] + N = 9 # number of slices + dz = z/(N-1) + dPhi = angle/(N-1) + for i in range(0, N): + t = i*1./(N-1) + xside = x1 + t*(x2 - x1) + yside = y1 + t*(y2 - y1) + v1 = FreeCAD.Vector(-xside/2, -yside/2, -z/2 + i*dz) + v2 = FreeCAD.Vector( xside/2, -yside/2, -z/2 + i*dz) + v3 = FreeCAD.Vector( xside/2, yside/2, -z/2 + i*dz) + v4 = FreeCAD.Vector(-xside/2, yside/2, -z/2 + i*dz) + p = Part.makePolygon([v1, v2, v3, v4, v1]) + p.rotate(FreeCAD.Vector(0, 0, 0), + FreeCAD.Vector(0, 0, 1), -angle/2 + i*dPhi) + slices.append(p) + + loft = Part.makeLoft(slices, True, False) + fp.Shape = loft + fp.Placement = currPlacement + + def OnDocumentRestored(self, obj): + print('Doc Restored') + + +class GDMLTwistedtubs(GDMLsolid): + def __init__(self, obj, endinnerrad, endouterrad, zlen, twistedangle, + phi, aunit, lunit, material, colour=None): + super().__init__(obj) + '''Twisted tube''' + obj.addProperty("App::PropertyFloat", "zlen", "GDMLTwistedtubs", + "zlen").zlen = zlen + obj.addProperty("App::PropertyFloat", "endinnerrad", "GDMLTwistedtubs", + "Inside radius at caps").endinnerrad = endinnerrad + obj.addProperty("App::PropertyFloat", "endouterrad", "GDMLTwistedtubs", + "Outside radius at caps").endouterrad = endouterrad + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLTwistedtubs", + "lunit") + angle = getAngleDeg(aunit, twistedangle) + if angle > 90: + print(f'PhiTwist angle cannot be larger than 90 deg') + angle = 90 + aunit = "deg" + elif angle < -90: + print(f'PhiTwist angle cannot be less than -90 deg') + angle = -90 + aunit = "deg" + else: + angle = twistedangle + + obj.addProperty("App::PropertyFloat", "twistedangle", "GDMLTwistedtubs", + "Twist Angle").twistedangle = angle + obj.addProperty("App::PropertyFloat", "phi", "GDMLTwistedtubs", + "Delta phi").phi = phi + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLTwistedtubs", + "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLTwistedtubs", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLTwistedtubs' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + # Changing Shape in createGeometry will redrive onChanged + if ('Restore' in fp.State): + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['endinnerrad', 'endouterrad', 'zlen', 'twistedangle', + 'phi', 'lunit', 'aunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + # print('createGeometry') + # print(fp) + + if all((fp.endouterrad, fp.zlen, fp.phi)): + currPlacement = fp.Placement + + mul = GDMLShared.getMult(fp) + rin = (fp.endinnerrad * mul) + rout = (fp.endouterrad * mul) + if rin > rout: + print(f'Erro: Inner radius ({rin}) greater than outer radius ({rout})') + return + zlen = (fp.zlen * mul) + GDMLShared.trace('mul : ' + str(mul)) + angle = getAngleDeg(fp.aunit, fp.twistedangle) + phi = getAngleRad(fp.aunit, fp.phi) + phideg = getAngleDeg(fp.aunit, fp.phi) + slices = [] + N = 9 # number of slices + dz = zlen/(N-1) + dtwist = angle/(N-1) + # construct base wire + # Vertexes + v1 = FreeCAD.Vector(rin, 0, 0) + v2 = FreeCAD.Vector(rout, 0, 0) + v3 = FreeCAD.Vector(rout*math.cos(phi), rout*math.sin(phi), 0) + v4 = FreeCAD.Vector(rin*math.cos(phi), rin*math.sin(phi), 0) + # arc center points + vCin = FreeCAD.Vector(rin*math.cos(phi/2), rin*math.sin(phi/2), 0) + vCout = FreeCAD.Vector(rout*math.cos(phi/2), rout*math.sin(phi/2), 0) + # Center of twisting + rc = (rin + rout)/2 + vc = FreeCAD.Vector(rc*math.cos(phi/2), rc*math.sin(phi/2), 0) + # wire + arcin = Part.Arc(v1, vCin, v4) + line1 = Part.LineSegment(v4, v3) + arcout = Part.Arc(v3, vCout, v2) + line2 = Part.LineSegment(v2, v1) + + s = Part.Shape([arcin, line1, arcout, line2]) + w = Part.Wire(s.Edges) + angoffset = -angle/2 - phideg/2 + + for i in range(0, N): + p = w.translated(FreeCAD.Vector(0, 0, -zlen/2 + i*dz)) + p.rotate(vc, FreeCAD.Vector(0, 0, 1), angoffset + i*dtwist) + slices.append(p) + + loft = Part.makeLoft(slices, True, False) + fp.Shape = loft + fp.Placement = currPlacement + + def OnDocumentRestored(self, obj): + print('Doc Restored') - def layerPoints(self,polyList,sf,xOffset,yOffset,zPosition): - vl = [] - for p in polyList : - #print(p) - vl.append(FreeCAD.Vector(p[0]*sf+xOffset, p[1]*sf+yOffset,zPosition)) - # Close list - vl.append(vl[0]) - return vl - - def createGeometry(self,fp): - #GDMLShared.setTrace(True) - currPlacement = fp.Placement - #print("Create Geometry") - parms = fp.OutList - #print("OutList") - #print(parms) - GDMLShared.trace("Number of parms : "+str(len(parms))) - polyList = [] - faceList = [] - sections = [] - mul = GDMLShared.getMult(fp) - for ptr in parms : - if hasattr(ptr,'x') : - x = ptr.x * mul - y = ptr.y * mul - GDMLShared.trace('x : '+str(x)) - GDMLShared.trace('y : '+str(y)) - polyList.append([x, y]) - if hasattr(ptr,'zOrder') : - zOrder = ptr.zOrder - xOffset = ptr.xOffset * mul - yOffset = ptr.yOffset * mul - zPosition = ptr.zPosition * mul - sf = ptr.scalingFactor * mul - s = [zOrder,xOffset,yOffset,zPosition,sf] - sections.append(s) - #print('sections : '+str(len(sections))) - # - # Deal with Base Face - # - #baseList = layerPoints(polyList,sf,xOffset,yOffset,zPosition): - baseList = self.layerPoints(polyList,sections[0][4],sections[0][1], \ - sections[0][2],sections[0][3]) - #print('baseList') - #print(baseList) - w1 = Part.makePolygon(baseList) - f1 = Part.Face(w1) - f1.reverse() - faceList.append(f1) - #print("base list") - # - # Deal with Sides - # - #print("Start Range "+str(len(sections)-1)) - for s in range(0,len(sections)-1) : - xOffset = sections[s+1][1] - yOffset = sections[s+1][2] - zPosition = sections[s+1][3] - sf2 = sections[s+1][4] - #layerList = layerPoints(polyList,sf,xOffset,yOffset,zPosition) - layerList = self.layerPoints(polyList,sf,xOffset,yOffset,zPosition) - # deal with side faces - # remember first point is added to end of list - #print("Number Sides : "+str(len(baseList)-1)) - for i in range(0,len(baseList)-2) : - sideList = [] - sideList.append(baseList[i]) - sideList.append(baseList[i+1]) - sideList.append(layerList[i+1]) - sideList.append(layerList[i]) - # Close SideList polygon - sideList.append(baseList[i]) - #print("sideList") - #print(sideList) - w1 = Part.makePolygon(sideList) - f1 = Part.Face(w1) - faceList.append(f1) - # - # Deal with Top Face - # - w1 = Part.makePolygon(layerList) - f1 = Part.Face(w1) - #f1.reverse() - faceList.append(f1) - #print("Faces List") - #print(faceList) - shell=Part.makeShell(faceList) - #solid=Part.Solid(shell).removeSplitter() - solid=Part.Solid(shell) - #print("Valid Solid : "+str(solid.isValid())) - if solid.Volume < 0: - solid.reverse() - #print(dir(fp)) - #solid.exportBrep("/tmp/"+fp.Label+".brep") - fp.Shape = solid - fp.Placement = currPlacement - -class GDML2dVertex(GDMLcommon) : - def __init__(self, obj, x, y): - super().__init__(obj) - obj.addProperty("App::PropertyString","Type","Vertex", \ - "twoDimVertex").Type='twoDimVertex' - obj.addProperty("App::PropertyFloat","x","Vertex", \ - "x").x=x - obj.addProperty("App::PropertyFloat","y","Vertex", \ - "y").y=y - obj.setEditorMode("Type", 1) - self.Type = 'Vertex' - self.Object = obj - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - #if prop in ['x','y'] : - # self.execute(fp) - #GDMLShared.trace("Change property: " + str(prop) + "\n") - pass - - def execute(self, fp): - pass - -class GDMLSection(GDMLcommon) : - def __init__(self, obj, zOrder,zPosition,xOffset,yOffset,scalingFactor): - super().__init__(obj) - obj.addProperty("App::PropertyString","Type","section", \ - "section").Type='section' - obj.addProperty("App::PropertyInteger","zOrder","section", \ - "zOrder").zOrder=zOrder - obj.addProperty("App::PropertyFloat","zPosition","section", \ - "zPosition").zPosition=zPosition - obj.addProperty("App::PropertyFloat","xOffset","section", \ - "xOffset").xOffset=xOffset - obj.addProperty("App::PropertyFloat","yOffset","section", \ - "yOffset").yOffset=yOffset - obj.addProperty("App::PropertyFloat","scalingFactor","section", \ - "scalingFactor").scalingFactor=scalingFactor - obj.setEditorMode("Type", 1) - self.Type = 'section' - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - #if prop in ['zOrder','zPosition','xOffset','yOffset','scaleFactor'] : - # self.execute(fp) - #GDMLShared.trace("Change property: " + str(prop) + "\n") - pass - - def execute(self, fp): - pass - -class GDMLzplane(GDMLcommon) : - def __init__(self, obj, rmin, rmax, z): - super().__init__(obj) - obj.addProperty("App::PropertyFloat","rmin","zplane", \ - "Inside Radius").rmin=rmin - obj.addProperty("App::PropertyFloat","rmax","zplane", \ - "Outside Radius").rmax=rmax - obj.addProperty("App::PropertyFloat","z","zplane","z").z=z - self.Type = 'zplane' - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - #if not ('Restore' in fp.State) : - #if prop in ['rmin','rmax','z'] : - # self.execute(fp) - #GDMLShared.trace("Change property: " + str(prop) + "\n") - pass - - def execute(self, fp): - pass - -class GDMLrzpoint(GDMLcommon) : - def __init__(self, obj, r, z): - super().__init__(obj) - obj.addProperty("App::PropertyFloat","r","rzpoint", \ - "r-coordinate").r=r - obj.addProperty("App::PropertyFloat","z","rzpoint","z-coordinate").z=z - self.Type = 'zplane' - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - #if not ('Restore' in fp.State) : - #if prop in ['rmin','rmax','z'] : - # self.execute(fp) - #GDMLShared.trace("Change property: " + str(prop) + "\n") - pass - - def execute(self, fp): - pass - -class GDMLPolycone(GDMLsolid) : # Thanks to Dam Lamb - def __init__(self, obj, startphi, deltaphi, aunit, lunit, material, colour = None) : - super().__init__(obj) - '''Add some custom properties to our Polycone feature''' - obj.addExtension('App::GroupExtensionPython') - obj.addProperty("App::PropertyFloat","startphi","GDMLPolycone", \ - "Start Angle").startphi=startphi - obj.addProperty("App::PropertyFloat","deltaphi","GDMLPolycone", \ - "Delta Angle").deltaphi=deltaphi - obj.addProperty("App::PropertyEnumeration","aunit","GDMLPolycone","aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLPolycone","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLPolycone", \ - "Material") - setMaterial(obj, material) - # For debugging - #obj.setEditorMode('Placement',0) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLPolycone' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['startphi','deltaphi','aunit','lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp) : - - currPlacement = fp.Placement - zplanes = fp.OutList - #GDMLShared.trace("Number of zplanes : "+str(len(zplanes))) - mul = GDMLShared.getMult(fp.lunit) - offset = zplanes[0].z * mul - angleDeltaPhiDeg = 360.0 - if (hasattr(fp,'deltaphi')) : - angleDeltaPhiDeg = min([getAngleDeg(fp.aunit,fp.deltaphi), angleDeltaPhiDeg]) - if(angleDeltaPhiDeg <=0.0): return - - listShape = [0 for i in range((len(zplanes)-1))] - - sinPhi = 0.0 - cosPhi = 1.0 - if fp.startphi != 0 : - angleRad = getAngleRad(fp.aunit,fp.startphi) - sinPhi = math.sin(angleRad) - cosPhi = math.cos(angleRad) - - # loops on each z level - for i in range(len(zplanes)-1) : - GDMLShared.trace('index : '+str(i)) - if i == 0: - rmin1 = zplanes[i].rmin * mul - rmax1 = zplanes[i].rmax * mul - z1 = zplanes[i].z * mul - offset - else: - rmin1 = rmin2 - rmax1 = rmax2 - z1 = z2 - - rmin2 = zplanes[i+1].rmin * mul - rmax2 = zplanes[i+1].rmax * mul - z2 = zplanes[i+1].z * mul - offset - - # def of one face to rotate - face = Part.Face(Part.makePolygon( [ \ - FreeCAD.Vector(rmin1*cosPhi,rmin1*sinPhi,z1), - FreeCAD.Vector(rmax1*cosPhi,rmax1*sinPhi,z1), - FreeCAD.Vector(rmax2*cosPhi,rmax2*sinPhi,z2), - FreeCAD.Vector(rmin2*cosPhi,rmin2*sinPhi,z2), - FreeCAD.Vector(rmin1*cosPhi,rmin1*sinPhi,z1)])) - # rotation of the face - listShape[i] = face.revolve(FreeCAD.Vector(0,0,0),FreeCAD.Vector(0,0,1),angleDeltaPhiDeg) - # compound of all faces - fp.Shape = Part.makeCompound(listShape) - fp.Placement = currPlacement - -class GDMLGenericPolycone(GDMLsolid) : # Thanks to Dam Lamb - def __init__(self, obj, startphi, deltaphi, aunit, lunit, material, colour = None) : - super().__init__(obj) - '''Add some custom properties to our GenericPolycone feature''' - obj.addExtension('App::GroupExtensionPython') - obj.addProperty("App::PropertyFloat","startphi","GDMLPolycone", \ - "Start Angle").startphi=startphi - obj.addProperty("App::PropertyFloat","deltaphi","GDMLPolycone", \ - "Delta Angle").deltaphi=deltaphi - obj.addProperty("App::PropertyEnumeration","aunit","GDMLPolycone","aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLPolycone","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLPolycone", \ - "Material") - setMaterial(obj, material) - # For debugging - #obj.setEditorMode('Placement',0) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLGenericPolycone' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - if prop in ['startphi','deltaphi','aunit','lunit'] : - self.createGeometry(fp) +class GDMLXtru(GDMLsolid): + def __init__(self, obj, lunit, material, colour=None): + super().__init__(obj) + obj.addExtension('App::GroupExtensionPython') + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLXtru", "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLXtru", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLXtru' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['startphi', 'deltaphi', 'aunit', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def layerPoints(self, polyList, sf, xOffset, yOffset, zPosition): + vl = [] + for p in polyList: + # print(p) + vl.append(FreeCAD.Vector(p[0]*sf+xOffset, p[1]*sf+yOffset, + zPosition)) + # Close list + vl.append(vl[0]) + return vl + + def createGeometry(self, fp): + # GDMLShared.setTrace(True) + currPlacement = fp.Placement + # print("Create Geometry") + parms = fp.OutList + # print("OutList") + # print(parms) + GDMLShared.trace("Number of parms : " + str(len(parms))) + polyList = [] + faceList = [] + sections = [] + mul = GDMLShared.getMult(fp) + for ptr in parms: + if hasattr(ptr, 'x'): + x = ptr.x * mul + y = ptr.y * mul + GDMLShared.trace('x : '+str(x)) + GDMLShared.trace('y : '+str(y)) + polyList.append([x, y]) + if hasattr(ptr, 'zOrder'): + zOrder = ptr.zOrder + xOffset = ptr.xOffset * mul + yOffset = ptr.yOffset * mul + zPosition = ptr.zPosition * mul + sf = ptr.scalingFactor * mul + s = [zOrder, xOffset, yOffset, zPosition, sf] + sections.append(s) + # print('sections : '+str(len(sections))) + # + # Deal with Base Face + # + # baseList = layerPoints(polyList,sf,xOffset,yOffset,zPosition): + baseList = self.layerPoints(polyList, sections[0][4], sections[0][1], + sections[0][2], sections[0][3]) + # print('baseList') + # print(baseList) + w1 = Part.makePolygon(baseList) + f1 = Part.Face(w1) + f1.reverse() + faceList.append(f1) + # print("base list") + # + # Deal with Sides + # + # print("Start Range "+str(len(sections)-1)) + for s in range(0, len(sections)-1): + xOffset = sections[s+1][1] + yOffset = sections[s+1][2] + zPosition = sections[s+1][3] + sf2 = sections[s+1][4] + # layerList = layerPoints(polyList,sf,xOffset,yOffset,zPosition) + layerList = self.layerPoints(polyList, sf, xOffset, yOffset, zPosition) + # deal with side faces + # remember first point is added to end of list + # print("Number Sides : "+str(len(baseList)-1)) + for i in range(0, len(baseList)-2): + sideList = [] + sideList.append(baseList[i]) + sideList.append(baseList[i+1]) + sideList.append(layerList[i+1]) + sideList.append(layerList[i]) + # Close SideList polygon + sideList.append(baseList[i]) + # print("sideList") + # print(sideList) + w1 = Part.makePolygon(sideList) + f1 = Part.Face(w1) + faceList.append(f1) + # + # Deal with Top Face + # + w1 = Part.makePolygon(layerList) + f1 = Part.Face(w1) + # f1.reverse() + faceList.append(f1) + # print("Faces List") + # print(faceList) + shell = Part.makeShell(faceList) + # solid=Part.Solid(shell).removeSplitter() + solid = Part.Solid(shell) + # print("Valid Solid : "+str(solid.isValid())) + if solid.Volume < 0: + solid.reverse() + # print(dir(fp)) + # solid.exportBrep("/tmp/"+fp.Label+".brep") + fp.Shape = solid + fp.Placement = currPlacement - #def execute(self, fp): in GDMLsolid - def createGeometry(self,fp) : +class GDML2dVertex(GDMLcommon): + def __init__(self, obj, x, y): + super().__init__(obj) + obj.addProperty("App::PropertyString", "Type", "Vertex", + "twoDimVertex").Type = 'twoDimVertex' + obj.addProperty("App::PropertyFloat", "x", "Vertex", + "x").x = x + obj.addProperty("App::PropertyFloat", "y", "Vertex", + "y").y = y + obj.setEditorMode("Type", 1) + self.Type = 'Vertex' + self.Object = obj + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + # if prop in ['x','y'] : + # self.execute(fp) + # GDMLShared.trace("Change property: " + str(prop) + "\n") + pass + + def execute(self, fp): + pass + + +class GDMLSection(GDMLcommon): + def __init__(self, obj, zOrder, zPosition, xOffset, yOffset, scalingFactor): + super().__init__(obj) + obj.addProperty("App::PropertyString", "Type", "section", + "section").Type = 'section' + obj.addProperty("App::PropertyInteger", "zOrder", "section", + "zOrder").zOrder = zOrder + obj.addProperty("App::PropertyFloat", "zPosition", "section", + "zPosition").zPosition = zPosition + obj.addProperty("App::PropertyFloat", "xOffset", "section", + "xOffset").xOffset = xOffset + obj.addProperty("App::PropertyFloat", "yOffset", "section", + "yOffset").yOffset = yOffset + obj.addProperty("App::PropertyFloat", "scalingFactor", "section", + "scalingFactor").scalingFactor = scalingFactor + obj.setEditorMode("Type", 1) + self.Type = 'section' + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + # if prop in ['zOrder','zPosition','xOffset','yOffset','scaleFactor'] : + # self.execute(fp) + # GDMLShared.trace("Change property: " + str(prop) + "\n") + pass + + def execute(self, fp): + pass + + +class GDMLzplane(GDMLcommon): + def __init__(self, obj, rmin, rmax, z): + super().__init__(obj) + obj.addProperty("App::PropertyFloat", "rmin", "zplane", + "Inside Radius").rmin = rmin + obj.addProperty("App::PropertyFloat", "rmax", "zplane", + "Outside Radius").rmax = rmax + obj.addProperty("App::PropertyFloat", "z", "zplane", "z").z = z + self.Type = 'zplane' + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + # if not ('Restore' in fp.State) : + # if prop in ['rmin','rmax','z'] : + # self.execute(fp) + # GDMLShared.trace("Change property: " + str(prop) + "\n") + pass + + def execute(self, fp): + pass + + +class GDMLrzpoint(GDMLcommon): + def __init__(self, obj, r, z): + super().__init__(obj) + obj.addProperty("App::PropertyFloat", "r", "rzpoint", + "r-coordinate").r = r + obj.addProperty("App::PropertyFloat", "z", "rzpoint", + "z-coordinate").z = z + self.Type = 'zplane' + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + # if not ('Restore' in fp.State) : + # if prop in ['rmin','rmax','z'] : + # self.execute(fp) + # GDMLShared.trace("Change property: " + str(prop) + "\n") + pass + + def execute(self, fp): + pass + + +class GDMLPolycone(GDMLsolid): # Thanks to Dam Lamb + def __init__(self, obj, startphi, deltaphi, aunit, lunit, material, + colour=None): + super().__init__(obj) + '''Add some custom properties to our Polycone feature''' + obj.addExtension('App::GroupExtensionPython') + obj.addProperty("App::PropertyFloat", "startphi", "GDMLPolycone", + "Start Angle").startphi = startphi + obj.addProperty("App::PropertyFloat", "deltaphi", "GDMLPolycone", + "Delta Angle").deltaphi = deltaphi + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLPolycone", + "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLPolycone", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLPolycone", + "Material") + setMaterial(obj, material) + # For debugging + # obj.setEditorMode('Placement',0) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLPolycone' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['startphi', 'deltaphi', 'aunit', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): - currPlacement = fp.Placement - rzpoints = fp.OutList - if len(rzpoints) < 3: - print("Error in genericPolycone: number of rzpoints less than 3") - return + currPlacement = fp.Placement + zplanes = fp.OutList + # GDMLShared.trace("Number of zplanes : "+str(len(zplanes))) + mul = GDMLShared.getMult(fp.lunit) + offset = zplanes[0].z * mul + angleDeltaPhiDeg = 360.0 + if (hasattr(fp, 'deltaphi')): + angleDeltaPhiDeg = min([getAngleDeg(fp.aunit, fp.deltaphi), + angleDeltaPhiDeg]) + if(angleDeltaPhiDeg <= 0.0): + return + + listShape = [0 for i in range((len(zplanes)-1))] + + sinPhi = 0.0 + cosPhi = 1.0 + if fp.startphi != 0: + angleRad = getAngleRad(fp.aunit, fp.startphi) + sinPhi = math.sin(angleRad) + cosPhi = math.cos(angleRad) + + # loops on each z level + for i in range(len(zplanes)-1): + GDMLShared.trace('index : ' + str(i)) + if i == 0: + rmin1 = zplanes[i].rmin * mul + rmax1 = zplanes[i].rmax * mul + z1 = zplanes[i].z * mul - offset + else: + rmin1 = rmin2 # for i > 0, rmin2 will have been defined below + rmax1 = rmax2 + z1 = z2 + + rmin2 = zplanes[i+1].rmin * mul + rmax2 = zplanes[i+1].rmax * mul + z2 = zplanes[i+1].z * mul - offset + + # def of one face to rotate + face = Part.Face(Part.makePolygon([ + FreeCAD.Vector(rmin1*cosPhi, rmin1*sinPhi, z1), + FreeCAD.Vector(rmax1*cosPhi, rmax1*sinPhi, z1), + FreeCAD.Vector(rmax2*cosPhi, rmax2*sinPhi, z2), + FreeCAD.Vector(rmin2*cosPhi, rmin2*sinPhi, z2), + FreeCAD.Vector(rmin1*cosPhi, rmin1*sinPhi, z1)])) + # rotation of the face + listShape[i] = face.revolve(FreeCAD.Vector(0, 0, 0), + FreeCAD.Vector(0, 0, 1), + angleDeltaPhiDeg) + # compound of all faces + fp.Shape = Part.makeCompound(listShape) + fp.Placement = currPlacement - deltaphi = getAngleDeg(fp.aunit, fp.deltaphi) - startphi = getAngleDeg(fp.aunit, fp.startphi) - - mul = GDMLShared.getMult(fp.lunit) - rr = [rz.r*mul for rz in rzpoints] - zz = [rz.z*mul for rz in rzpoints] - verts = [FreeCAD.Vector(rz.r*mul, 0, rz.z*mul) for rz in rzpoints] - verts.append(FreeCAD.Vector(rzpoints[0].r*mul, 0, rzpoints[0].z*mul) ) - line = Part.makePolygon(verts) - line.rotate(FreeCAD.Vector(0,0,0), FreeCAD.Vector(0,0,1), startphi) - face = Part.Face(line) - surf = face.revolve(FreeCAD.Vector(0,0,0), FreeCAD.Vector(0,0,1), deltaphi) - solid = Part.makeSolid(surf) - - fp.Shape = solid - fp.Placement = currPlacement - -class GDMLSphere(GDMLsolid) : - def __init__(self, obj, rmin, rmax, startphi, deltaphi, starttheta, \ - deltatheta, aunit, lunit, material, colour = None ): - super().__init__(obj) - '''Add some custom properties to our Sphere feature''' - GDMLShared.trace("GDMLSphere init") - obj.addProperty("App::PropertyFloat","rmin","GDMLSphere", \ - "Inside Radius").rmin=rmin - obj.addProperty("App::PropertyFloat","rmax","GDMLSphere", \ - "Outside Radius").rmax=rmax - obj.addProperty("App::PropertyFloat","startphi","GDMLSphere", \ - "Start Angle").startphi=startphi - obj.addProperty("App::PropertyFloat","deltaphi","GDMLSphere", \ - "Delta Angle").deltaphi=deltaphi - obj.addProperty("App::PropertyFloat","starttheta","GDMLSphere", \ - "Start Theta pos").starttheta=starttheta - obj.addProperty("App::PropertyFloat","deltatheta","GDMLSphere", \ - "Delta Angle").deltatheta=deltatheta - obj.addProperty("App::PropertyEnumeration","aunit","GDMLSphere","aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLSphere","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLSphere", \ - "Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - obj.Proxy = self - self.Type = 'GDMLSphere' - self.colour = colour - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['rmin','rmax','startphi','deltaphi','starttheta', \ - 'deltatheta','aunit','lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - # Based on code by Dam Lamb - currPlacement = fp.Placement - mul = GDMLShared.getMult(fp) - rmax = mul * fp.rmax - if rmax <= 0.0: return - Rmax = 2 * rmax - rmin = mul * fp.rmin - spos = FreeCAD.Vector(0,0,0) - sdir = FreeCAD.Vector(0,0,1) - HalfPi = math.pi / 2.0 - TwoPi = 2 * math.pi - deltaphi_deg = getAngleDeg(fp.aunit, fp.deltaphi) - if deltaphi_deg < 360.0 and deltaphi_deg > 0: - sphere2 = Part.makeSphere(rmax,spos,sdir, \ - -90.0, 90.0, \ - deltaphi_deg) - if fp.startphi != 0 : - sphere2.rotate(spos, sdir, getAngleDeg(fp.aunit,fp.startphi)) - else : + +class GDMLGenericPolycone(GDMLsolid): # Thanks to Dam Lamb + def __init__(self, obj, startphi, deltaphi, aunit, lunit, material, + colour=None): + super().__init__(obj) + '''Add some custom properties to our GenericPolycone feature''' + obj.addExtension('App::GroupExtensionPython') + obj.addProperty("App::PropertyFloat", "startphi", "GDMLPolycone", + "Start Angle").startphi = startphi + obj.addProperty("App::PropertyFloat", "deltaphi", "GDMLPolycone", + "Delta Angle").deltaphi = deltaphi + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLPolycone", + "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLPolycone", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLPolycone", + "Material") + setMaterial(obj, material) + # For debugging + # obj.setEditorMode('Placement',0) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLGenericPolycone' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['startphi', 'deltaphi', 'aunit', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + + currPlacement = fp.Placement + rzpoints = fp.OutList + if len(rzpoints) < 3: + print("Error in genericPolycone: number of rzpoints less than 3") + return + + deltaphi = getAngleDeg(fp.aunit, fp.deltaphi) + startphi = getAngleDeg(fp.aunit, fp.startphi) + + mul = GDMLShared.getMult(fp.lunit) + verts = [FreeCAD.Vector(rz.r*mul, 0, rz.z*mul) for rz in rzpoints] + verts.append(FreeCAD.Vector(rzpoints[0].r*mul, 0, rzpoints[0].z*mul)) + line = Part.makePolygon(verts) + line.rotate(FreeCAD.Vector(0, 0, 0), + FreeCAD.Vector(0, 0, 1), startphi) + face = Part.Face(line) + surf = face.revolve(FreeCAD.Vector(0, 0, 0), + FreeCAD.Vector(0, 0, 1), deltaphi) + solid = Part.makeSolid(surf) + + fp.Shape = solid + fp.Placement = currPlacement + + +class GDMLSphere(GDMLsolid): + def __init__(self, obj, rmin, rmax, startphi, deltaphi, starttheta, + deltatheta, aunit, lunit, material, colour=None ): + super().__init__(obj) + '''Add some custom properties to our Sphere feature''' + GDMLShared.trace("GDMLSphere init") + obj.addProperty("App::PropertyFloat", "rmin", "GDMLSphere", + "Inside Radius").rmin = rmin + obj.addProperty("App::PropertyFloat", "rmax", "GDMLSphere", + "Outside Radius").rmax = rmax + obj.addProperty("App::PropertyFloat", "startphi", "GDMLSphere", + "Start Angle").startphi = startphi + obj.addProperty("App::PropertyFloat", "deltaphi", "GDMLSphere", + "Delta Angle").deltaphi = deltaphi + obj.addProperty("App::PropertyFloat", "starttheta", "GDMLSphere", + "Start Theta pos").starttheta = starttheta + obj.addProperty("App::PropertyFloat", "deltatheta", "GDMLSphere", + "Delta Angle").deltatheta = deltatheta + obj.addProperty("App::PropertyEnumeration", "aunit", + "GDMLSphere", "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLSphere", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLSphere", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + obj.Proxy = self + self.Type = 'GDMLSphere' + self.colour = colour + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['rmin', 'rmax', 'startphi', 'deltaphi', 'starttheta', + 'deltatheta', 'aunit', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + # Based on code by Dam Lamb + currPlacement = fp.Placement + mul = GDMLShared.getMult(fp) + rmax = mul * fp.rmax + if rmax <= 0.0: + return + Rmax = 2 * rmax + rmin = mul * fp.rmin + spos = FreeCAD.Vector(0, 0, 0) + sdir = FreeCAD.Vector(0, 0, 1) + HalfPi = math.pi / 2.0 + TwoPi = 2 * math.pi + deltaphi_deg = getAngleDeg(fp.aunit, fp.deltaphi) + if deltaphi_deg < 360.0 and deltaphi_deg > 0: + sphere2 = Part.makeSphere(rmax, spos, sdir, + -90.0, 90.0, + deltaphi_deg) + if fp.startphi != 0: + sphere2.rotate(spos, sdir, getAngleDeg(fp.aunit, fp.startphi)) + else: sphere2 = Part.makeSphere(rmax) - # if starttheta > 0 cut the upper cone - startthetaRad = getAngleRad(fp.aunit, fp.starttheta) - startthetaDeg = getAngleDeg(fp.aunit, fp.starttheta) - - if startthetaDeg > 0.0 : - if startthetaDeg == 90.0 : - cylToCut = Part.makeCylinder(2.0*rmax,rmax, \ - FreeCAD.Vector(0,0,0)) + # if starttheta > 0 cut the upper cone + startthetaRad = getAngleRad(fp.aunit, fp.starttheta) + startthetaDeg = getAngleDeg(fp.aunit, fp.starttheta) + + if startthetaDeg > 0.0: + if startthetaDeg == 90.0: + cylToCut = Part.makeCylinder(2.0*rmax, rmax, + FreeCAD.Vector(0, 0, 0)) sphere2 = sphere2.cut(cylToCut) - elif startthetaDeg < 90.0 : - sphere2 = sphere2.cut(Part.makeCone(0.0, \ - rmax*math.sin(startthetaRad), rmax*math.cos(startthetaRad))) - - cylToCut = Part.makeCylinder(2.0*rmax,rmax, \ - FreeCAD.Vector(0,0,rmax*math.cos(startthetaRad))) - sphere2 = sphere2.cut(cylToCut) - - elif startthetaDeg < 180.0 : - sphere2 = sphere2.common(Part.makeCone(0.0, \ - rmax/math.cos(math.pi-startthetaRad),rmax, spos, \ - FreeCAD.Vector(0,0,-1.0))) - - # if deltatheta -> cut the down cone - deltathetaRad = getAngleRad(fp.aunit, fp.deltatheta) - thetaSumRad= startthetaRad + deltathetaRad - if thetaSumRad < math.pi : - if thetaSumRad > HalfPi : - - sphere2 = sphere2.cut(Part.makeCone(0.0, \ - rmax*math.sin(math.pi - thetaSumRad), \ - rmax*math.cos(math.pi - thetaSumRad), \ - spos, FreeCAD.Vector(0,0,-1.0))) - - cylToCut = Part.makeCylinder(2.0*rmax,rmax, \ - FreeCAD.Vector(0,0,rmax*(-1.0 + math.cos(thetaSumRad))) ) - sphere2 = sphere2.cut(cylToCut) - - elif thetaSumRad == HalfPi : - cylToCut = Part.makeCylinder(2.0*rmax,rmax, \ - FreeCAD.Vector(0,0,-rmax)) + elif startthetaDeg < 90.0: + sphere2 = sphere2.cut(Part.makeCone( + 0.0, + rmax*math.sin(startthetaRad), + rmax*math.cos(startthetaRad))) + + cylToCut = Part.makeCylinder( + 2.0*rmax, rmax, + FreeCAD.Vector(0, 0, rmax*math.cos(startthetaRad))) sphere2 = sphere2.cut(cylToCut) - elif thetaSumRad > 0 : - sphere2 = sphere2.common(Part.makeCone(0.0, \ - 2*rmax*math.tan( thetaSumRad), \ - 2*rmax )) - - if rmin <= 0 or rmin > rmax : - fp.Shape = sphere2 - else : - fp.Shape = sphere2.cut(Part.makeSphere(rmin)) - fp.Placement = currPlacement - - -class GDMLTrap(GDMLsolid) : - def __init__(self, obj, z, theta, phi, x1, x2, x3, x4, y1, y2, alpha, \ - aunit, lunit, material, colour = None): - super().__init__(obj) - "General Trapezoid" - obj.addProperty("App::PropertyFloat","z","GDMLTrap","z").z=z - obj.addProperty("App::PropertyFloat","theta","GDMLTrap","theta"). \ - theta=theta - obj.addProperty("App::PropertyFloat","phi","GDMLTrap","phi").phi=phi - obj.addProperty("App::PropertyFloat","x1","GDMLTrap", \ - "Length x at y= -y1/2 of face at -z/2").x1=x1 - obj.addProperty("App::PropertyFloat","x2","GDMLTrap", \ - "Length x at y= +y1/2 of face at -z/2").x2=x2 - obj.addProperty("App::PropertyFloat","x3","GDMLTrap", \ - "Length x at y= -y2/2 of face at +z/2").x3=x3 - obj.addProperty("App::PropertyFloat","x4","GDMLTrap", \ - "Length x at y= +y2/2 of face at +z/2").x4=x4 - obj.addProperty("App::PropertyFloat","y1","GDMLTrap", \ - "Length y at face -z/2").y1=y1 - obj.addProperty("App::PropertyFloat","y2","GDMLTrap", \ - "Length y at face +z/2").y2=y2 - obj.addProperty("App::PropertyFloat","alpha","GDMLTrap","alpha"). \ - alpha=alpha - obj.addProperty("App::PropertyEnumeration","aunit","GDMLTrap","aunit") - obj.aunit=["rad", "deg"] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLTrap","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLTrap","Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - obj.Proxy = self - self.Type = 'GDMLTrap' - self.colour = colour - - def onChanged(self, fp, prop): - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['z','theta','phi','x1','x2','x3','x4','y1','y2','alpha', \ - 'aunit', 'lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - # Define six vetices for the shape - alpha = getAngleRad(fp.aunit,fp.alpha) - theta = getAngleRad(fp.aunit,fp.theta) - phi = getAngleRad(fp.aunit,fp.phi) - mul = GDMLShared.getMult(fp) - y1 = mul * fp.y1 - x1 = mul * fp.x1 - x2 = mul * fp.x2 - y2 = mul * fp.y2 - x3 = mul * fp.x3 - x4 = mul * fp.x4 - z = mul * fp.z - dx1 = y1*math.tan(alpha) - dx2 = y2*math.tan(alpha) - - #Vertexes, counter clock wise order - v1 = FreeCAD.Vector(-x1/2 - dx1/2, -y1/2, -z/2) - v2 = FreeCAD.Vector( x1/2 - dx1/2, -y1/2, -z/2) - v3 = FreeCAD.Vector( x2/2 + dx1/2, y1/2, -z/2) - v4 = FreeCAD.Vector(-x2/2 + dx1/2, y1/2, -z/2) - v5 = FreeCAD.Vector(-x3/2 - dx2/2, -y2/2, z/2) - v6 = FreeCAD.Vector( x3/2 - dx2/2, -y2/2, z/2) - v7 = FreeCAD.Vector( x4/2 + dx2/2, y2/2, z/2) - v8 = FreeCAD.Vector(-x4/2 + dx2/2, y2/2, z/2) - # - # xy faces - # - vxy1 = [v1, v4, v3, v2, v1] - vxy2 = [v5, v6, v7, v8, v5] - # - # zx faces - # - vzx1 = [v1, v2, v6, v5, v1] - vzx2 = [v3, v4, v8, v7, v3] - # - # yz faces - # - vyz1 = [v5, v8, v4, v1, v5] - vyz2 = [v2, v3, v7, v6, v2] - # - # apply theta, phi distortions - # - rho = z*math.tan(theta) - dx = rho*math.cos(phi) - dy = rho*math.sin(phi) - for i in range(0,4): - vxy1[i][0] -= dx/2 - vxy1[i][1] -= dy/2 - vxy2[i][0] += dx/2 - vxy2[i][1] += dy/2 + + elif startthetaDeg < 180.0: + sphere2 = sphere2.common(Part.makeCone( + 0.0, + rmax/math.cos(math.pi-startthetaRad), rmax, spos, + FreeCAD.Vector(0, 0, -1.0))) + + # if deltatheta -> cut the down cone + deltathetaRad = getAngleRad(fp.aunit, fp.deltatheta) + thetaSumRad = startthetaRad + deltathetaRad + if thetaSumRad < math.pi: + if thetaSumRad > HalfPi: + + sphere2 = sphere2.cut(Part.makeCone( + 0.0, + rmax*math.sin(math.pi - thetaSumRad), + rmax*math.cos(math.pi - thetaSumRad), + spos, FreeCAD.Vector(0, 0, -1.0))) + + cylToCut = Part.makeCylinder( + 2.0*rmax, rmax, + FreeCAD.Vector(0, 0, rmax*(-1.0 + math.cos(thetaSumRad)))) + sphere2 = sphere2.cut(cylToCut) + + elif thetaSumRad == HalfPi: + cylToCut = Part.makeCylinder(2.0*rmax, rmax, + FreeCAD.Vector(0, 0, -rmax)) + sphere2 = sphere2.cut(cylToCut) + elif thetaSumRad > 0: + sphere2 = sphere2.common(Part.makeCone( + 0.0, + 2*rmax*math.tan(thetaSumRad), + 2*rmax)) + + if rmin <= 0 or rmin > rmax: + fp.Shape = sphere2 + else: + fp.Shape = sphere2.cut(Part.makeSphere(rmin)) + fp.Placement = currPlacement + + +class GDMLTrap(GDMLsolid): + def __init__(self, obj, z, theta, phi, x1, x2, x3, x4, y1, y2, alpha, + aunit, lunit, material, colour=None): + super().__init__(obj) + "General Trapezoid" + obj.addProperty("App::PropertyFloat", "z", "GDMLTrap", "z").z = z + obj.addProperty("App::PropertyFloat", "theta", "GDMLTrap", + "theta").theta = theta + obj.addProperty("App::PropertyFloat", "phi", "GDMLTrap", + "phi").phi = phi + obj.addProperty("App::PropertyFloat", "x1", "GDMLTrap", + "Length x at y= -y1/2 of face at -z/2").x1 = x1 + obj.addProperty("App::PropertyFloat", "x2", "GDMLTrap", + "Length x at y= +y1/2 of face at -z/2").x2 = x2 + obj.addProperty("App::PropertyFloat", "x3", "GDMLTrap", + "Length x at y= -y2/2 of face at +z/2").x3 = x3 + obj.addProperty("App::PropertyFloat", "x4", "GDMLTrap", + "Length x at y= +y2/2 of face at +z/2").x4 = x4 + obj.addProperty("App::PropertyFloat", "y1", "GDMLTrap", + "Length y at face -z/2").y1 = y1 + obj.addProperty("App::PropertyFloat", "y2", "GDMLTrap", + "Length y at face +z/2").y2 = y2 + obj.addProperty("App::PropertyFloat", "alpha", "GDMLTrap", + "alpha").alpha = alpha + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLTrap", "aunit") + obj.aunit = ["rad", "deg"] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLTrap", "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLTrap", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + obj.Proxy = self + self.Type = 'GDMLTrap' + self.colour = colour + + def onChanged(self, fp, prop): + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['z', 'theta', 'phi', + 'x1', 'x2', 'x3', 'x4', 'y1', 'y2', 'alpha', + 'aunit', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self,fp): + currPlacement = fp.Placement + # Define six vetices for the shape + alpha = getAngleRad(fp.aunit,fp.alpha) + theta = getAngleRad(fp.aunit,fp.theta) + phi = getAngleRad(fp.aunit,fp.phi) + mul = GDMLShared.getMult(fp) + y1 = mul * fp.y1 + x1 = mul * fp.x1 + x2 = mul * fp.x2 + y2 = mul * fp.y2 + x3 = mul * fp.x3 + x4 = mul * fp.x4 + z = mul * fp.z + dx1 = y1*math.tan(alpha) + dx2 = y2*math.tan(alpha) - fxy1 = Part.Face(Part.makePolygon(vxy1)) - fxy2 = Part.Face(Part.makePolygon(vxy2)) - fzx1 = Part.Face(Part.makePolygon(vzx1)) - fzx2 = Part.Face(Part.makePolygon(vzx2)) - fyz1 = Part.Face(Part.makePolygon(vyz1)) - fyz2 = Part.Face(Part.makePolygon(vyz2)) - - shell = Part.makeShell([fxy1, fxy2, fzx1, fzx2, fyz1, fyz2]) - solid = Part.makeSolid(shell) - - # center is mid point of diagonal - # - botCenter = ((v3+v4) + (v1+v2))/2 - topCenter = ((v7+v8) + (v5+v6))/2 - center = (topCenter+botCenter)/2 - - fp.Shape = translate(solid, -center) - fp.Placement = currPlacement - - -class GDMLTrd(GDMLsolid) : - def __init__(self, obj, z, x1, x2, y1, y2, lunit, material, colour = None) : - super().__init__(obj) - "3.4.15 : Trapezoid – x & y varying along z" - obj.addProperty("App::PropertyFloat","z","GDMLTrd`","z").z=z - obj.addProperty("App::PropertyFloat","x1","GDMLTrd", \ - "Length x at face -z/2").x1=x1 - obj.addProperty("App::PropertyFloat","x2","GDMLTrd", \ - "Length x at face +z/2").x2=x2 - obj.addProperty("App::PropertyFloat","y1","GDMLTrd", \ - "Length y at face -z/2").y1=y1 - obj.addProperty("App::PropertyFloat","y2","GDMLTrd", \ - "Length y at face +z/2").y2=y2 - obj.addProperty("App::PropertyEnumeration","lunit","GDMLTrd","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLTrd","Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - obj.Proxy = self - self.Type = 'GDMLTrd' - self.colour = colour - - def onChanged(self, fp, prop): - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['z','x1','x2','y1','y2','lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - GDMLShared.trace("x2 : "+str(fp.x2)) - - mul = GDMLShared.getMult(fp) - x1 = (fp.x1 * mul)/2 - x2 = (fp.x2 * mul)/2 - y1 = (fp.y1 * mul)/2 - y2 = (fp.y2 * mul)/2 - z = (fp.z * mul)/2 - v1 = FreeCAD.Vector(-x1, -y1, -z) - v2 = FreeCAD.Vector(-x1, +y1, -z) - v3 = FreeCAD.Vector(x1, +y1, -z) - v4 = FreeCAD.Vector(x1, -y1, -z) - - v5 = FreeCAD.Vector(-x2, -y2, z) - v6 = FreeCAD.Vector(-x2, +y2, z) - v7 = FreeCAD.Vector(x2, +y2, z) - v8 = FreeCAD.Vector(x2, -y2, z) - # Make the wires/faces - f1 = make_face4(v1,v2,v3,v4) - f2 = make_face4(v1,v2,v6,v5) - f3 = make_face4(v2,v3,v7,v6) - f4 = make_face4(v3,v4,v8,v7) - f5 = make_face4(v1,v4,v8,v5) - f6 = make_face4(v5,v6,v7,v8) - shell=Part.makeShell([f1,f2,f3,f4,f5,f6]) - solid=Part.makeSolid(shell) - - #solid = Part.makePolygon([v1,v2,v3,v4,v5,v6,v7,v1]) - - fp.Shape = solid - fp.Placement = currPlacement - -class GDMLTube(GDMLsolid) : - def __init__(self, obj, rmin, rmax, z, startphi, deltaphi, aunit, \ - lunit, material, colour = None): - super().__init__(obj) - '''Add some custom properties to our Tube feature''' - obj.addProperty("App::PropertyFloat","rmin","GDMLTube","Inside Radius").rmin=rmin - obj.addProperty("App::PropertyFloat","rmax","GDMLTube","Outside Radius").rmax=rmax - obj.addProperty("App::PropertyFloat","z","GDMLTube","Length z").z=z - obj.addProperty("App::PropertyFloat","startphi","GDMLTube","Start Angle").startphi=startphi - obj.addProperty("App::PropertyFloat","deltaphi","GDMLTube","Delta Angle").deltaphi=deltaphi - obj.addProperty("App::PropertyEnumeration","aunit","GDMLTube","aunit") - obj.aunit=['rad','deg'] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLTube","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLTube","Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - obj.Proxy = self - self.Type = 'GDMLTube' - self.colour = colour - - def onChanged(self, fp, prop): - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['rmin','rmax','z','startphi','deltaphi','aunit', \ - 'lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - mul = GDMLShared.getMult(fp) - rmax = mul * fp.rmax - rmin = mul * fp.rmin - z = mul * fp.z - spos = FreeCAD.Vector(0,0,0) - sdir = FreeCAD.Vector(0,0,1) - #print('mul : '+str(mul)) - #print('rmax : '+str(rmax)) - #print('z : '+str(z)) - #print('deltaPhi : '+str(fp.deltaphi)) - tube = Part.makeCylinder(rmax, z, spos, sdir, - getAngleDeg(fp.aunit, fp.deltaphi)) - - if fp.startphi != 0 : - tube.rotate(spos, sdir, getAngleDeg(fp.aunit,fp.startphi)) - - if rmin > 0 : - tube = tube.cut(Part.makeCylinder(rmin, z)) - - base = FreeCAD.Vector(0,0,-z/2) - fp.Shape = translate(tube,base) - fp.Placement = currPlacement - -class GDMLcutTube(GDMLsolid) : - def __init__(self, obj, rmin, rmax, z, startphi, deltaphi, aunit, \ - lowX, lowY, lowZ, highX, highY, highZ, \ - lunit, material, colour = None): - super().__init__(obj) - '''Add some custom properties to our Tube feature''' - obj.addProperty("App::PropertyFloat","rmin","GDMLcutTube","Inside Radius").rmin=rmin - obj.addProperty("App::PropertyFloat","rmax","GDMLcutTube","Outside Radius").rmax=rmax - obj.addProperty("App::PropertyFloat","z","GDMLcutTube","Length z").z=z - obj.addProperty("App::PropertyFloat","startphi","GDMLcutTube","Start Angle").startphi=startphi - obj.addProperty("App::PropertyFloat","deltaphi","GDMLcutTube","Delta Angle").deltaphi=deltaphi - obj.addProperty("App::PropertyEnumeration","aunit","GDMLcutTube","aunit") - obj.aunit=['rad','deg'] - obj.aunit=['rad','deg'].index(aunit[0:3]) - obj.addProperty("App::PropertyFloat","lowX","GDMLcutTube","low X").lowX=lowX - obj.addProperty("App::PropertyFloat","lowY","GDMLcutTube","low Y").lowY=lowY - obj.addProperty("App::PropertyFloat","lowZ","GDMLcutTube","low Z").lowZ=lowZ - obj.addProperty("App::PropertyFloat","highX","GDMLcutTube","high X").highX=highX - obj.addProperty("App::PropertyFloat","highY","GDMLcutTube","high Y").highY=highY - obj.addProperty("App::PropertyFloat","highZ","GDMLcutTube","high Z").highZ=highZ - obj.addProperty("App::PropertyEnumeration","lunit","GDMLcutTube","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLcutTube","Material") - #print('Add material') - #print(material) - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - #print(MaterialsList) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - obj.Proxy = self - self.Type = 'GDMLcutTube' - self.colour = colour - - def onChanged(self, fp, prop): - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return + # Vertexes, counter clock wise order + v1 = FreeCAD.Vector(-x1/2 - dx1/2, -y1/2, -z/2) + v2 = FreeCAD.Vector( x1/2 - dx1/2, -y1/2, -z/2) + v3 = FreeCAD.Vector( x2/2 + dx1/2, y1/2, -z/2) + v4 = FreeCAD.Vector(-x2/2 + dx1/2, y1/2, -z/2) + v5 = FreeCAD.Vector(-x3/2 - dx2/2, -y2/2, z/2) + v6 = FreeCAD.Vector( x3/2 - dx2/2, -y2/2, z/2) + v7 = FreeCAD.Vector( x4/2 + dx2/2, y2/2, z/2) + v8 = FreeCAD.Vector(-x4/2 + dx2/2, y2/2, z/2) + # + # xy faces + # + vxy1 = [v1, v4, v3, v2, v1] + vxy2 = [v5, v6, v7, v8, v5] + # + # zx faces + # + vzx1 = [v1, v2, v6, v5, v1] + vzx2 = [v3, v4, v8, v7, v3] + # + # yz faces + # + vyz1 = [v5, v8, v4, v1, v5] + vyz2 = [v2, v3, v7, v6, v2] + # + # apply theta, phi distortions + # + rho = z*math.tan(theta) + dx = rho*math.cos(phi) + dy = rho*math.sin(phi) + for i in range(0, 4): + vxy1[i][0] -= dx/2 + vxy1[i][1] -= dy/2 + vxy2[i][0] += dx/2 + vxy2[i][1] += dy/2 + + fxy1 = Part.Face(Part.makePolygon(vxy1)) + fxy2 = Part.Face(Part.makePolygon(vxy2)) + fzx1 = Part.Face(Part.makePolygon(vzx1)) + fzx2 = Part.Face(Part.makePolygon(vzx2)) + fyz1 = Part.Face(Part.makePolygon(vyz1)) + fyz2 = Part.Face(Part.makePolygon(vyz2)) + + shell = Part.makeShell([fxy1, fxy2, fzx1, fzx2, fyz1, fyz2]) + solid = Part.makeSolid(shell) + + # center is mid point of diagonal + # + botCenter = ((v3+v4) + (v1+v2))/2 + topCenter = ((v7+v8) + (v5+v6))/2 + center = (topCenter+botCenter)/2 + + fp.Shape = translate(solid, -center) + fp.Placement = currPlacement + + +class GDMLTrd(GDMLsolid): + def __init__(self, obj, z, x1, x2, y1, y2, lunit, material, colour=None): + super().__init__(obj) + "3.4.15 : Trapezoid – x & y varying along z" + obj.addProperty("App::PropertyFloat", "z", "GDMLTrd", + "z").z = z + obj.addProperty("App::PropertyFloat", "x1", "GDMLTrd", + "Length x at face -z/2").x1 = x1 + obj.addProperty("App::PropertyFloat", "x2", "GDMLTrd", + "Length x at face +z/2").x2 = x2 + obj.addProperty("App::PropertyFloat", "y1", "GDMLTrd", + "Length y at face -z/2").y1 = y1 + obj.addProperty("App::PropertyFloat", "y2", "GDMLTrd", + "Length y at face +z/2").y2 = y2 + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLTrd", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLTrd", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + obj.Proxy = self + self.Type = 'GDMLTrd' + self.colour = colour + + def onChanged(self, fp, prop): + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['z', 'x1', 'x2', 'y1', 'y2', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + GDMLShared.trace("x2 : " + str(fp.x2)) + + mul = GDMLShared.getMult(fp) + x1 = (fp.x1 * mul)/2 + x2 = (fp.x2 * mul)/2 + y1 = (fp.y1 * mul)/2 + y2 = (fp.y2 * mul)/2 + z = (fp.z * mul)/2 + v1 = FreeCAD.Vector(-x1, -y1, -z) + v2 = FreeCAD.Vector(-x1, +y1, -z) + v3 = FreeCAD.Vector(x1, +y1, -z) + v4 = FreeCAD.Vector(x1, -y1, -z) + + v5 = FreeCAD.Vector(-x2, -y2, z) + v6 = FreeCAD.Vector(-x2, +y2, z) + v7 = FreeCAD.Vector(x2, +y2, z) + v8 = FreeCAD.Vector(x2, -y2, z) + # Make the wires/faces + f1 = make_face4(v1, v2, v3, v4) + f2 = make_face4(v1, v2, v6, v5) + f3 = make_face4(v2, v3, v7, v6) + f4 = make_face4(v3, v4, v8, v7) + f5 = make_face4(v1, v4, v8, v5) + f6 = make_face4(v5, v6, v7, v8) + shell = Part.makeShell([f1, f2, f3, f4, f5, f6]) + solid = Part.makeSolid(shell) + + # solid = Part.makePolygon([v1,v2,v3,v4,v5,v6,v7,v1]) + + fp.Shape = solid + fp.Placement = currPlacement + + +class GDMLTube(GDMLsolid): + def __init__(self, obj, rmin, rmax, z, startphi, deltaphi, aunit, + lunit, material, colour=None): + super().__init__(obj) + '''Add some custom properties to our Tube feature''' + obj.addProperty("App::PropertyFloat", "rmin", "GDMLTube", + "Inside Radius").rmin = rmin + obj.addProperty("App::PropertyFloat", "rmax", "GDMLTube", + "Outside Radius").rmax = rmax + obj.addProperty("App::PropertyFloat", "z", "GDMLTube", + "Length z").z = z + obj.addProperty("App::PropertyFloat", "startphi", "GDMLTube", + "Start Angle").startphi = startphi + obj.addProperty("App::PropertyFloat", "deltaphi", "GDMLTube", + "Delta Angle").deltaphi = deltaphi + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLTube", + "aunit") + obj.aunit = ['rad', 'deg'] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLTube", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLTube", + "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + obj.Proxy = self + self.Type = 'GDMLTube' + self.colour = colour + + def onChanged(self, fp, prop): + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) - if prop in ['rmin','rmax','z','startphi','deltaphi','aunit', \ - 'lowX', 'lowY', 'lowZ', \ - 'highX','highY','highZ','lunit'] : - self.createGeometry(fp) + if prop in ['rmin', 'rmax', 'z', 'startphi', 'deltaphi', + 'aunit', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + mul = GDMLShared.getMult(fp) + rmax = mul * fp.rmax + rmin = mul * fp.rmin + z = mul * fp.z + spos = FreeCAD.Vector(0, 0, 0) + sdir = FreeCAD.Vector(0, 0, 1) + # print('mul : '+str(mul)) + # print('rmax : '+str(rmax)) + # print('z : '+str(z)) + # print('deltaPhi : '+str(fp.deltaphi)) + tube = Part.makeCylinder(rmax, z, spos, sdir, + getAngleDeg(fp.aunit, fp.deltaphi)) + + if fp.startphi != 0: + tube.rotate(spos, sdir, getAngleDeg(fp.aunit, fp.startphi)) + + if rmin > 0: + tube = tube.cut(Part.makeCylinder(rmin, z)) + + base = FreeCAD.Vector(0, 0, -z/2) + fp.Shape = translate(tube, base) + fp.Placement = currPlacement - #def execute(self, fp): in GDMLsolid - def cutShapeWithPlane(self, shape, plane, depth): +class GDMLcutTube(GDMLsolid): + def __init__(self, obj, rmin, rmax, z, startphi, deltaphi, aunit, + lowX, lowY, lowZ, highX, highY, highZ, + lunit, material, colour=None): + super().__init__(obj) + '''Add some custom properties to our Tube feature''' + obj.addProperty("App::PropertyFloat", "rmin", "GDMLcutTube", + "Inside Radius").rmin = rmin + obj.addProperty("App::PropertyFloat", "rmax", "GDMLcutTube", + "Outside Radius").rmax = rmax + obj.addProperty("App::PropertyFloat", "z", "GDMLcutTube", + "Length z").z = z + obj.addProperty("App::PropertyFloat", "startphi", "GDMLcutTube", + "Start Angle").startphi = startphi + obj.addProperty("App::PropertyFloat", "deltaphi", "GDMLcutTube", + "Delta Angle").deltaphi = deltaphi + obj.addProperty("App::PropertyEnumeration", "aunit", "GDMLcutTube", + "aunit") + obj.aunit = ['rad', 'deg'] + obj.aunit = ['rad', 'deg'].index(aunit[0:3]) + obj.addProperty("App::PropertyFloat", "lowX", "GDMLcutTube", + "low X").lowX = lowX + obj.addProperty("App::PropertyFloat", "lowY", "GDMLcutTube", + "low Y").lowY = lowY + obj.addProperty("App::PropertyFloat", "lowZ", "GDMLcutTube", + "low Z").lowZ = lowZ + obj.addProperty("App::PropertyFloat", "highX", "GDMLcutTube", + "high X").highX = highX + obj.addProperty("App::PropertyFloat", "highY", "GDMLcutTube", + "high Y").highY = highY + obj.addProperty("App::PropertyFloat", "highZ", "GDMLcutTube", + "high Z").highZ = highZ + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLcutTube", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", "GDMLcutTube", + "Material") + # print('Add material') + # print(material) + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # print(MaterialsList) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + obj.Proxy = self + self.Type = 'GDMLcutTube' + self.colour = colour + + def onChanged(self, fp, prop): + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['rmin', 'rmax', 'z', 'startphi', 'deltaphi', 'aunit', + 'lowX', 'lowY', 'lowZ', + 'highX', 'highY', 'highZ', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def cutShapeWithPlane(self, shape, plane, depth): "Cut a shape with a plane" - #print('Cut Shape with Plane') - #print('depth : '+str(depth)) - #so = plane.extrude(plane.*1e10) - #so = plane.extrude(plane.normalAt(1,1)*1e10) - #so = plane.extrude(plane.normalAt(1,1)*100) - so = plane.extrude(plane.normalAt(1,1)*depth) - #print('Plane extruded') - #print(plane.normalAt(1,1)) - #return so - #print('Extrude made - Now Cut') + # print('Cut Shape with Plane') + # print('depth : '+str(depth)) + # so = plane.extrude(plane.*1e10) + # so = plane.extrude(plane.normalAt(1,1)*1e10) + # so = plane.extrude(plane.normalAt(1,1)*100) + so = plane.extrude(plane.normalAt(1, 1)*depth) + # print('Plane extruded') + # print(plane.normalAt(1,1)) + # return so + # print('Extrude made - Now Cut') cut = shape.cut(so) - #print('Return Cut') + # print('Return Cut') return cut - def createGeometry(self,fp): + def createGeometry(self, fp): currPlacement = fp.Placement - angle = getAngleDeg(fp.aunit,fp.deltaphi) - pntC = FreeCAD.Vector(0,0,0) - dirC = FreeCAD.Vector(0,0,1) - mul = GDMLShared.getMult(fp) - #print('mul : '+str(mul)) + angle = getAngleDeg(fp.aunit, fp.deltaphi) + pntC = FreeCAD.Vector(0, 0, 0) + dirC = FreeCAD.Vector(0, 0, 1) + mul = GDMLShared.getMult(fp) rmin = mul * fp.rmin - #print('rmin : '+str(rmin)) - #print(type(fp.rmin)) rmax = mul * fp.rmax - #print('rmax : '+str(rmax)) - z = mul * fp.z - #print('z : '+str(z)) - depth = 2 * max(rmax,z) - #print('depth : '+str(depth)) - #print(fp.lowX) - #print(fp.lowY) - #print(fp.lowZ) + z = mul * fp.z + depth = 2 * max(rmax, z) botDir = FreeCAD.Vector(fp.lowX, fp.lowY, fp.lowZ) topDir = FreeCAD.Vector(fp.highX, fp.highY, fp.highZ) - tube1 = Part.makeCylinder(rmax,z,pntC,dirC,angle) - tube2 = Part.makeCylinder(rmin,z,pntC,dirC,angle) + tube1 = Part.makeCylinder(rmax, z, pntC, dirC, angle) + tube2 = Part.makeCylinder(rmin, z, pntC, dirC, angle) tube = tube1.cut(tube2) - #Part.show(tube1) - #print('Create top Plane') - topPlane = Part.makePlane(depth, depth, \ - FreeCAD.Vector(-rmax,-rmax,z),topDir) - #Part.show(topPlane) - #print('Cut top Plane') - cutTube1 = self.cutShapeWithPlane(tube, topPlane, depth) - #Part.show(cutTube1) - #print('Create BottomPlane') - botPlane = Part.makePlane(depth, depth, \ - FreeCAD.Vector(rmax,rmax,0.0),botDir) - #botPlane = Part.makePlane(500, 500, \ - # FreeCAD.Vector(rmax,rmax,0.0),FreeCAD.Vector(0.0,-0.7,-0.71)) - #Part.show(botPlane) - #print('Cut Top Plane') - cutTube2 = self.cutShapeWithPlane(cutTube1,botPlane,depth) - #print('Return result') - #fp.Shape = Part.makeBox(2,2,2) - base = FreeCAD.Vector(0,0,-z/2) - fp.Shape = translate(cutTube2,base) - #fp.Shape = topPlane - #fp.Shape = botPlane + topPlane = Part.makePlane(depth, depth, + FreeCAD.Vector(-rmax, -rmax, z), topDir) + cutTube1 = self.cutShapeWithPlane(tube, topPlane, depth) + botPlane = Part.makePlane(depth, depth, + FreeCAD.Vector(rmax, rmax, 0.0), botDir) + cutTube2 = self.cutShapeWithPlane(cutTube1, botPlane, depth) + base = FreeCAD.Vector(0, 0, -z/2) + fp.Shape = translate(cutTube2, base) fp.Placement = currPlacement - def createGeometry_hardcoded(self,fp): - angle = getAngleDeg(fp.aunit,fp.deltaphi) - pntC = FreeCAD.Vector(0,0,0) - dirC = FreeCAD.Vector(0,0,1) - #pntP = FreeCAD.Vector(-5,-5,5) + def createGeometry_hardcoded(self, fp): + angle = getAngleDeg(fp.aunit, fp.deltaphi) + pntC = FreeCAD.Vector(0, 0, 0) + dirC = FreeCAD.Vector(0, 0, 1) - tube1 = Part.makeCylinder(20,60,pntC,dirC,angle) - tube2 = Part.makeCylinder(12,60,pntC,dirC,angle) + tube1 = Part.makeCylinder(20, 60, pntC, dirC, angle) + tube2 = Part.makeCylinder(12, 60, pntC, dirC, angle) tube = tube1.cut(tube2) - #Part.show(tube1) - #print('Create top Plane') - topPlane = Part.makePlane(100, 100, \ - FreeCAD.Vector(-20,-20,60),FreeCAD.Vector(0.7,0,0.71)) - #Part.show(topPlane) - print('Cut top Plane') - cutTube1 = self.cutShapeWithPlane(tube, topPlane) - #Part.show(cutTube1) - print('Create BottomPlane') - botPlane = Part.makePlane(100, 100, \ - FreeCAD.Vector(20,20,0),FreeCAD.Vector(0,-0.7,-0.71)) + topPlane = Part.makePlane(100, 100, + FreeCAD.Vector(-20, -20, 60), + FreeCAD.Vector(0.7, 0, 0.71)) + cutTube1 = self.cutShapeWithPlane(tube, topPlane) + botPlane = Part.makePlane(100, 100, + FreeCAD.Vector(20, 20, 0), + FreeCAD.Vector(0, -0.7, -0.71)) Part.show(botPlane) - print('Cut Top Plane') - cutTube2 = self.cutShapeWithPlane(cutTube1,botPlane) - #cutTube2 = self.cutShapeWithPlane(tube,botPlane) + cutTube2 = self.cutShapeWithPlane(cutTube1, botPlane) print('Return result') - #fp.Shape = Part.makeBox(2,2,2) fp.Shape = cutTube2 - #fp.Shape = tube - #fp.Shape = topPlane - -class GDMLVertex(GDMLcommon) : - def __init__(self, obj, x, y, z, lunit): - super().__init__(obj) - obj.addProperty("App::PropertyFloat","x","GDMLVertex", \ - "x").x=x - obj.addProperty("App::PropertyFloat","y","GDMLVertex", \ - "y").y=y - obj.addProperty("App::PropertyFloat","z","GDMLVertex", \ - "z").z=z - self.Type = 'GDMLVertex' - self.Object = obj - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - #if not ('Restore' in fp.State) : - # if prop in ['x','y', 'z'] : - # self.execute(fp) - #GDMLShared.trace("Change property: " + str(prop) + "\n") - pass - - def execute(self, fp): - pass - -class GDMLTriangular(GDMLcommon) : - def __init__(self, obj, v1, v2, v3, vtype): - super().__init__(obj) - obj.addProperty("App::PropertyVector","v1","Triangular", \ - "v1").v1=v1 - obj.addProperty("App::PropertyVector","v2","Triangular", \ - "v1").v2=v2 - obj.addProperty("App::PropertyVector","v3","Triangular", \ - "v1").v3=v3 - obj.addProperty("App::PropertyEnumeration","vtype","Triangular","vtype") - obj.vtype=["ABSOLUTE", "RELATIVE"] - obj.vtype=["ABSOLUTE", "RELATIVE"].index(vtype) - self.Type = 'GDMLTriangular' - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - #if not ('Restore' in fp.State) : - # if prop in ['v1','v2','v3','type'] : - # self.execute(fp) - #GDMLShared.trace("Change property: " + str(prop) + "\n") - pass - - def execute(self, fp): - pass - -class GDMLQuadrangular(GDMLcommon) : - def __init__(self, obj, v1, v2, v3, v4, vtype): - super().__init__(obj) - obj.addProperty("App::PropertyVector","v1","Quadrang", \ - "v1").v1=v1 - obj.addProperty("App::PropertyVector","v2","Quadrang", \ - "v2").v2=v2 - obj.addProperty("App::PropertyVector","v3","Quadrang", \ - "v3").v3=v3 - obj.addProperty("App::PropertyVector","v4","Quadrang", \ - "v4").v4=v4 - obj.addProperty("App::PropertyEnumeration","vtype","Quadrang","vtype") - obj.vtype=["ABSOLUTE", "RELATIVE"] - obj.vtype=0 - self.Type = 'GDMLQuadrangular' - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - #if prop in ['v1','v2','v3','v4','type'] : - # self.execute(fp) - #GDMLShared.trace("Change property: " + str(prop) + "\n") - pass - - def execute(self, fp): - pass - -class GDMLGmshTessellated(GDMLsolid) : - - def __init__(self, obj, sourceObj,meshLen, vertex, facets, lunit, \ - material, colour = None) : - super().__init__(obj) - #obj.addProperty('App::PropertyBool','editable','GDMLGmshTessellated', \ - # 'Editable').editable = False - obj.addProperty('App::PropertyInteger','facets','GDMLGmshTessellated', \ - 'Facets').facets = len(facets) - obj.setEditorMode('facets',1) - obj.addProperty('App::PropertyInteger','vertex','GDMLGmshTessellated', \ - 'Vertex').vertex = len(vertex) - obj.setEditorMode('vertex',1) - obj.addProperty('App::PropertyFloat','m_maxLength', \ - 'GDMLGmshTessellated', \ - 'Max Length').m_maxLength = meshLen - obj.addProperty('App::PropertyFloat','m_curveLen','GDMLGmshTessellated', \ - 'Curve Length').m_curveLen = meshLen - obj.addProperty('App::PropertyFloat','m_pointLen','GDMLGmshTessellated', \ - 'Point Length').m_pointLen = meshLen - #obj.addProperty('App::PropertyBool','m_Remesh','GDMLGmshTessellated', \ - # 'ReMesh').m_Remesh = False - obj.addProperty("App::PropertyEnumeration","lunit","GDMLGmshTessellated","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material", \ - "GDMLTessellated","Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - #print(MaterialsList) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - #obj.addExtension('App::GroupExtensionPython') - self.Type = 'GDMLGmshTessellated' - self.SourceObj = sourceObj - self.Vertex = vertex - self.Facets = facets - self.Object = obj - self.colour = colour - obj.Proxy = self - - def updateParams(self, vertex, facets) : - #print('Update Params') - self.Vertex = vertex - self.Facets = facets - self.facets = len(facets) - self.vertex = len(vertex) - print(f"Vertex : {self.vertex} Facets : {self.facets}") - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['editable'] : - if fp.editable == True : - self.addProperties() - - if prop in ['m_Remesh'] : - if fp.m_Remesh == True : - self.reMesh(fp) - self.execute(fp) - - #if prop in ['v1','v2','v3','v4','type','lunit'] : - # self.createGeometry(fp) - - def execute(self, fp): # Here for remesh? - self.createGeometry(fp) - - def addProperties(self) : - print('Add Properties') - - def reMesh(self,fp) : - from .GmshUtils import initialize, meshObj, getVertex, getFacets - - initialize() - meshObj(fp.Proxy.SourceObj,2,True,fp.Proxy.Object) - facets = getFacets() - vertex = getVertex() - fp.Proxy.Vertex = vertex - self.Object.vertex = len(vertex) - fp.Proxy.Facets = facets - self.Object.facets = len(facets) - FreeCADGui.updateGui() - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - currPlacement = fp.Placement - #print("Tessellated") - mul = GDMLShared.getMult(fp) - FCfaces = [] - #print(self.Vertex) - i = 0 - for f in self.Facets : - #print('Facet') - #print(f) - if len(f) == 3 : - FCfaces.append(GDMLShared.triangle( \ - mul*self.Vertex[f[0]], \ - mul*self.Vertex[f[1]], \ - mul*self.Vertex[f[2]])) - else : # len should then be 4 - FCfaces.append(GDMLShared.quad( \ - mul*self.Vertex[f[0]], \ - mul*self.Vertex[f[1]], \ - mul*self.Vertex[f[2]], \ - mul*self.Vertex[f[3]])) - shell=Part.makeShell(FCfaces) - if shell.isValid == False : - FreeCAD.Console.PrintWarning('Not a valid Shell/n') - - #shell.check() - #solid=Part.Solid(shell).removeSplitter() - try : - solid=Part.Solid(shell) - except : - # make compound rather than just barf - # visually able to view at least - FreeCAD.Console.PrintWarning('Problem making Solid/n') - solid = Part.makeCompound(FCfaces) - #if solid.Volume < 0: - # solid.reverse() - #print(dir(solid)) - #bbox = solid.BoundBox - #base = FreeCAD.Vector(-(bbox.XMin+bbox.XMax)/2, \ - # -(bbox.YMin+bbox.YMax)/2 \ - # -(bbox.ZMin+bbox.ZMax)/2) - #print(base) - - #base = FreeCAD.Vector(0,0,0) - #fp.Shape = translate(solid,base) - fp.Shape = solid - fp.Placement = currPlacement - -class GDMLTessellated(GDMLsolid) : - - def __init__(self, obj, vertex, facets, flag, lunit, material, colour = None) : - super().__init__(obj) - # ######################################## - # if flag == True - facets is Mesh.Facets - with Normals - # if flag == False - facets is Faces i.e. from import GDMLTessellated - # ######################################## - obj.addProperty('App::PropertyInteger','facets','GDMLTessellated', \ - 'Facets').facets = len(facets) - obj.setEditorMode('facets',1) - obj.addProperty('App::PropertyInteger','vertex','GDMLTessellated', \ - 'Vertex').vertex = len(vertex) - obj.setEditorMode('vertex',1) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLTessellated","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material", \ - "GDMLTessellated","Material") - setMaterial(obj, material) - self.updateParams(vertex, facets, flag) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - self.Type = 'GDMLTessellated' - self.colour = colour - obj.Proxy = self - - def updateParams(self, vertex, facets, flag) : - #print('Update Params & Shape') - self.pshape = self.createShape(vertex,facets,flag) - #print(f"Pshape vertex {len(self.pshape.Vertexes)}") - self.facets = len(facets) - self.vertex = len(vertex) - #print(f"Vertex : {self.vertex} Facets : {self.facets}") - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['editable'] : - if fp.editable == True : - self.addProperties() - - #if prop in ['v1','v2','v3','v4','type','lunit'] : - # self.createGeometry(fp) - - def addProperties(self) : - print('Add Properties') - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp): - #currPlacement = fp.Placement - #print("Tessellated") - #print(self.Type) - #print('self') - #print(dir(self)) - #print('fp') - #print(dir(fp)) - if hasattr(self,'pshape') : - #print('Update Shape') - fp.Shape = self.pshape - if hasattr(fp,'pshape') : - fp.pshape = self.pshape - fp.vertex = self.vertex - fp.facets = self.facets - #print(len(fp.Shape.Vertexes)) - #print(fp.Shape) - #fp.Placement = currPlacement - - def createShape(self,vertex,facets,flag) : - # Viewing outside of face vertex must be counter clockwise - # if flag == True - facets is Mesh.Facets - # if flag == False - factes is Faces i.e. from import GDMLTessellated - #mul = GDMLShared.getMult(fp) - mul = GDMLShared.getMult(self) - #print('Create Shape') - FCfaces = [] - i = 0 - for f in facets : - #print('Facet') - #print(f) - if flag == True : - FCfaces.append(GDMLShared.facet(f)) - else : - if len(f) == 3 : - FCfaces.append(GDMLShared.triangle( \ - mul*vertex[f[0]], \ - mul*vertex[f[1]], \ - mul*vertex[f[2]])) - else : # len should then be 4 - FCfaces.append(GDMLShared.quad( \ - mul*vertex[f[0]], \ - mul*vertex[f[1]], \ - mul*vertex[f[2]], \ - mul*vertex[f[3]])) - #print(FCfaces) - shell=Part.makeShell(FCfaces) - if shell.isValid == False : - FreeCAD.Console.PrintWarning('Not a valid Shell/n') - - #shell.check() - #solid=Part.Solid(shell).removeSplitter() - try : - solid=Part.Solid(shell) - except : - # make compound rather than just barf - # visually able to view at least - FreeCAD.Console.PrintWarning('Problem making Solid/n') - solid = Part.makeCompound(FCfaces) - #if solid.Volume < 0: - # solid.reverse() - #print(dir(solid)) - #bbox = solid.BoundBox - #base = FreeCAD.Vector(-(bbox.XMin+bbox.XMax)/2, \ - # -(bbox.YMin+bbox.YMax)/2 \ - # -(bbox.ZMin+bbox.ZMax)/2) - #print(base) - - #base = FreeCAD.Vector(0,0,0) - #fp.Shape = translate(solid,base) - #fp.Shape = solid - - return solid - -class GDMLTetra(GDMLsolid) : # 4 point Tetrahedron - - def __init__(self, obj, v1, v2, v3, v4, lunit, material, colour = None ): - super().__init__(obj) - obj.addProperty("App::PropertyVector","v1","GDMLTra", \ - "v1").v1=v1 - obj.addProperty("App::PropertyVector","v2","GDMLTra", \ - "v2").v2=v2 - obj.addProperty("App::PropertyVector","v3","GDMLTra", \ - "v3").v3=v3 - obj.addProperty("App::PropertyVector","v4","GDMLTra", \ - "v4").v4=v4 - obj.addProperty("App::PropertyEnumeration","lunit","GDMLTra","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material","GDMLTra","Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - self.Type = 'GDMLTetra' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - - if prop in ['v1','v2','v3','v4','lunit'] : - self.createGeometry(fp) - - #def execute(self, fp): in GDMLsolid - - def createGeometry(self,fp) : - currPlacement = fp.Placement - mul = GDMLShared.getMult(fp) - pt1 = mul * fp.v1 - pt2 = mul * fp.v2 - pt3 = mul * fp.v3 - pt4 = mul * fp.v4 - face1 = Part.Face(Part.makePolygon([pt1,pt2,pt3,pt1])) - face2 = Part.Face(Part.makePolygon([pt1,pt2,pt4,pt1])) - face3 = Part.Face(Part.makePolygon([pt4,pt2,pt3,pt4])) - face4 = Part.Face(Part.makePolygon([pt1,pt3,pt4,pt1])) - fp.Shape = Part.makeSolid(Part.makeShell([face1,face2,face3,face4])) - fp.Placement = currPlacement - -class GDMLTetrahedron(GDMLsolid) : - - ''' Does not exist as a GDML solid, but export as an Assembly of G4Tet ''' - ''' See paper Poole at al - Fast Tessellated solid navigation in GEANT4 ''' - - def __init__(self, obj, tetra, lunit, material, colour=None) : - super().__init__(obj) - #obj.addProperty('App::PropertyBool','editable','GDMLTetrahedron', \ - # 'Editable').editable = False - obj.addProperty('App::PropertyInteger','tetra','GDMLTetrahedron', \ - 'Tetra').tetra = len(tetra) - obj.setEditorMode('tetra',1) - obj.addProperty("App::PropertyEnumeration","lunit","GDMLTetrahedron","lunit") - setLengthQuantity(obj, lunit) - obj.addProperty("App::PropertyEnumeration","material", \ - "GDMLTetrahedron","Material") - setMaterial(obj, material) - if FreeCAD.GuiUp : - updateColour(obj,colour,material) - # Suppress Placement - position & Rotation via parent App::Part - # this makes Placement via Phyvol easier and allows copies etc - #obj.addExtension('App::GroupExtensionPython') - self.Tetra = tetra - self.Object = obj - self.Type = 'GDMLTetrahedron' - self.colour = colour - obj.Proxy = self - - def onChanged(self, fp, prop): - '''Do something when a property has changed''' - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - if 'Restore' in fp.State : - return - - if prop in ['material'] : - if FreeCAD.GuiUp : - if hasattr(self,'colour') : - if self.colour is None : - fp.ViewObject.ShapeColor = colourMaterial(fp.material) - if prop in ['lunit'] : - self.createGeometry(fp) - #def execute(self, fp): in GDMLsolid - - def makeTetra(self,pt1,pt2,pt3,pt4) : - face1 = Part.Face(Part.makePolygon([pt1,pt2,pt3,pt1])) - face2 = Part.Face(Part.makePolygon([pt1,pt2,pt4,pt1])) - face3 = Part.Face(Part.makePolygon([pt4,pt2,pt3,pt4])) - face4 = Part.Face(Part.makePolygon([pt1,pt3,pt4,pt1])) - return(Part.makeShell([face1,face2,face3,face4])) - #return(face1,face2,face3,face4) - - def createGeometry(self,fp): - currPlacement = fp.Placement - print("Tetrahedron") - mul = GDMLShared.getMult(fp) - print(len(self.Tetra)) - tetraShells = [] - for t in self.Tetra : - pt1 = mul * t[0] - pt2 = mul * t[1] - pt3 = mul * t[2] - pt4 = mul * t[3] - tetraShells.append(self.makeTetra(pt1,pt2,pt3,pt4)) - fp.Shape = Part.makeCompound(tetraShells) - fp.Placement = currPlacement - -class GDMLFiles(GDMLcommon) : - def __init__(self,obj,FilesEntity,sectionDict) : - super().__init__(obj) - '''Add some custom properties to our Cone feature''' - GDMLShared.trace("GDML Files") - GDMLShared.trace(FilesEntity) - obj.addProperty("App::PropertyBool","active","GDMLFiles", \ - "split option").active=FilesEntity - obj.addProperty("App::PropertyString","define","GDMLFiles", \ - "define section").define=sectionDict.get('define',"") - obj.addProperty("App::PropertyString","materials","GDMLFiles", \ - "materials section").materials=sectionDict.get('materials',"") - obj.addProperty("App::PropertyString","solids","GDMLFiles", \ - "solids section").solids=sectionDict.get('solids',"") - obj.addProperty("App::PropertyString","structure","GDMLFiles", \ - "structure section").structure=sectionDict.get('structure',"") - self.Type = 'GDMLFiles' - obj.Proxy = self - - def execute(self, fp): - '''Do something when doing a recomputation, this method is mandatory''' - pass - - def onChanged(self, fp, prop): - #print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) - #if not ('Restore' in fp.State) : - # if not hasattr(fp,'onchange') or not fp.onchange : return - pass - -class GDMLvolume : - def __init__(self,obj) : - obj.Proxy = self - self.Object = obj - -class GDMLconstant(GDMLcommon) : - def __init__(self,obj,name,value) : - super().__init__(obj) - obj.addProperty("App::PropertyString","name",'GDMLconstant','name').name = name - obj.addProperty("App::PropertyString","value",'GDMLconstant','value').value = value - obj.Proxy = self - self.Object = obj - -class GDMLvariable(GDMLcommon) : - def __init__(self,obj,name,value) : - super().__init__(obj) - obj.addProperty("App::PropertyString","name",'GDMLvariable','name').name = name - obj.addProperty("App::PropertyString","value",'GDMLvariable','value').value = value - obj.Proxy = self - self.Object = obj - -class GDMLquantity(GDMLcommon) : - def __init__(self,obj,name,type,unit,value) : - super().__init__(obj) - obj.addProperty("App::PropertyString","name",'GDMLvariable','name').name = name - obj.addProperty("App::PropertyString","type",'GDMLvariable','type').type = type - obj.addProperty("App::PropertyString","unit",'GDMLvariable','unit').unit = unit - obj.addProperty("App::PropertyString","value",'GDMLvariable','value').value = value - obj.Proxy = self - self.Object = obj - - -class GDMLmaterial(GDMLcommon) : - def __init__(self,obj,name,density=1.0,conduct=2.0,expand=3.0,specific=4.0) : - super().__init__(obj) - # Add most properties later - obj.addProperty("App::PropertyString","name",'GDMLmaterial','name').name = name - obj.addProperty("App::PropertyFloat","density","GDMLmaterial", \ - "Density kg/m^3").density = density - obj.addProperty("App::PropertyFloat","conduct","GDMLmaterial", \ - "Thermal Conductivity W/m/K").conduct = conduct - obj.addProperty("App::PropertyFloat","expand","GDMLmaterial", \ - "Expansion Coefficient m/m/K").expand = expand - obj.addProperty("App::PropertyFloat","specific","GDMLmaterial", - "Specific Heat J/kg/K").specific = specific - - obj.Proxy = self - self.Object = obj - -class GDMLfraction(GDMLcommon) : - def __init__(self,obj,ref,n) : - super().__init__(obj) - obj.addProperty("App::PropertyFloat",'n',ref).n = n - obj.Proxy = self - self.Object = obj - -class GDMLcomposite(GDMLcommon) : - def __init__(self,obj,name,n,ref) : - super().__init__(obj) - obj.addProperty("App::PropertyInteger","n",name).n = n - obj.addProperty("App::PropertyString","ref",name).ref = ref - obj.Proxy = self - self.Object = obj - -class GDMLelement(GDMLcommon) : - def __init__(self,obj,name) : - super().__init__(obj) - obj.addProperty("App::PropertyString","name",name).name = name - obj.Proxy = self - self.Object = obj - -class GDMLisotope(GDMLcommon) : - def __init__(self,obj,name,N,Z) : - super().__init__(obj) - obj.addProperty("App::PropertyString","name",name).name = name - obj.addProperty("App::PropertyInteger","N",name).N=N - obj.addProperty("App::PropertyInteger","Z",name).Z=Z - # Name, N and Z are minimum other values are added by import - #obj.addProperty("App::PropertyString","unit",name).unit = unit - #obj.addProperty("App::PropertyFloat","value",name).value = value - obj.Proxy = self - self.Object = obj - -class ViewProviderExtension(GDMLcommon) : - def __init__(self, obj): - super().__init__(obj) - obj.addExtension("Gui::ViewProviderGroupExtensionPython") - obj.Proxy = self - - def getDisplayModes(self,obj): - '''Return a list of display modes.''' - modes=[] - modes.append("Shaded") - modes.append("Wireframe") - return modes - - def updateData(self, fp, prop): - '''If a property of the handled feature has changed we have the chance to handle this here''' - # fp is the handled feature, prop is the name of the property that has changed - #l = fp.getPropertyByName("Length") - #w = fp.getPropertyByName("Width") - #h = fp.getPropertyByName("Height") - #self.scale.scaleFactor.setValue(float(l),float(w),float(h)) - pass - - def getDefaultDisplayMode(self): - '''Return the name of the default display mode. It must be defined in getDisplayModes.''' - return "Shaded" - +class GDMLVertex(GDMLcommon): + def __init__(self, obj, x, y, z, lunit): + super().__init__(obj) + obj.addProperty("App::PropertyFloat", "x", "GDMLVertex", + "x").x = x + obj.addProperty("App::PropertyFloat", "y", "GDMLVertex", + "y").y = y + obj.addProperty("App::PropertyFloat", "z", "GDMLVertex", + "z").z = z + self.Type = 'GDMLVertex' + self.Object = obj + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + # if not ('Restore' in fp.State) : + # if prop in ['x','y', 'z'] : + # self.execute(fp) + # GDMLShared.trace("Change property: " + str(prop) + "\n") + pass + + def execute(self, fp): + pass + + +class GDMLTriangular(GDMLcommon): + def __init__(self, obj, v1, v2, v3, vtype): + super().__init__(obj) + obj.addProperty("App::PropertyVector", "v1", "Triangular", + "v1").v1 = v1 + obj.addProperty("App::PropertyVector", "v2", "Triangular", + "v1").v2 = v2 + obj.addProperty("App::PropertyVector", "v3", "Triangular", + "v1").v3 = v3 + obj.addProperty("App::PropertyEnumeration", "vtype", "Triangular", + "vtype") + obj.vtype = ["ABSOLUTE", "RELATIVE"] + obj.vtype = ["ABSOLUTE", "RELATIVE"].index(vtype) + self.Type = 'GDMLTriangular' + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + pass + + def execute(self, fp): + pass + + +class GDMLQuadrangular(GDMLcommon): + def __init__(self, obj, v1, v2, v3, v4, vtype): + super().__init__(obj) + obj.addProperty("App::PropertyVector", "v1", "Quadrang", + "v1").v1 = v1 + obj.addProperty("App::PropertyVector", "v2", "Quadrang", + "v2").v2 = v2 + obj.addProperty("App::PropertyVector", "v3", "Quadrang", + "v3").v3 = v3 + obj.addProperty("App::PropertyVector", "v4", "Quadrang", + "v4").v4 = v4 + obj.addProperty("App::PropertyEnumeration", "vtype", + "Quadrang", "vtype") + obj.vtype = ["ABSOLUTE", "RELATIVE"] + obj.vtype = 0 + self.Type = 'GDMLQuadrangular' + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + if 'Restore' in fp.State: + return + + pass + + def execute(self, fp): + pass + + +class GDMLGmshTessellated(GDMLsolid): + + def __init__(self, obj, sourceObj, meshLen, vertex, facets, lunit, + material, colour=None): + super().__init__(obj) + obj.addProperty('App::PropertyInteger', 'facets', 'GDMLGmshTessellated', + 'Facets').facets = len(facets) + obj.setEditorMode('facets', 1) + obj.addProperty('App::PropertyInteger', 'vertex', 'GDMLGmshTessellated', + 'Vertex').vertex = len(vertex) + obj.setEditorMode('vertex', 1) + obj.addProperty('App::PropertyFloat', 'm_maxLength', + 'GDMLGmshTessellated', + 'Max Length').m_maxLength = meshLen + obj.addProperty('App::PropertyFloat', 'm_curveLen', + 'GDMLGmshTessellated', + 'Curve Length').m_curveLen = meshLen + obj.addProperty('App::PropertyFloat', 'm_pointLen', + 'GDMLGmshTessellated', + 'Point Length').m_pointLen = meshLen + obj.addProperty("App::PropertyEnumeration", "lunit", + "GDMLGmshTessellated", "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", + "GDMLTessellated", "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + self.Type = 'GDMLGmshTessellated' + self.SourceObj = sourceObj + self.Vertex = vertex + self.Facets = facets + self.Object = obj + self.colour = colour + obj.Proxy = self + + def updateParams(self, vertex, facets): + self.Vertex = vertex + self.Facets = facets + self.facets = len(facets) + self.vertex = len(vertex) + print(f"Vertex : {self.vertex} Facets : {self.facets}") + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['editable']: + if fp.editable is True: + self.addProperties() + + if prop in ['m_Remesh']: + if fp.m_Remesh is True: + self.reMesh(fp) + self.execute(fp) + + def execute(self, fp): # Here for remesh? + self.createGeometry(fp) + + def addProperties(self): + print('Add Properties') + + def reMesh(self, fp): + from .GmshUtils import initialize, meshObj, getVertex, getFacets + + initialize() + meshObj(fp.Proxy.SourceObj, 2, True, fp.Proxy.Object) + facets = getFacets() + vertex = getVertex() + fp.Proxy.Vertex = vertex + self.Object.vertex = len(vertex) + fp.Proxy.Facets = facets + self.Object.facets = len(facets) + FreeCADGui.updateGui() + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + mul = GDMLShared.getMult(fp) + FCfaces = [] + i = 0 + for f in self.Facets: + if len(f) == 3: + FCfaces.append(GDMLShared.triangle(mul*self.Vertex[f[0]], + mul*self.Vertex[f[1]], + mul*self.Vertex[f[2]])) + else: # len should then be 4 + FCfaces.append(GDMLShared.quad(mul*self.Vertex[f[0]], + mul*self.Vertex[f[1]], + mul*self.Vertex[f[2]], + mul*self.Vertex[f[3]])) + shell = Part.makeShell(FCfaces) + if shell.isValid is False: + FreeCAD.Console.PrintWarning('Not a valid Shell/n') + + try: + solid = Part.Solid(shell) + except: + # make compound rather than just barf + # visually able to view at least + FreeCAD.Console.PrintWarning('Problem making Solid/n') + solid = Part.makeCompound(FCfaces) + # if solid.Volume < 0: + # solid.reverse() + # print(dir(solid)) + # bbox = solid.BoundBox + # base = FreeCAD.Vector(-(bbox.XMin+bbox.XMax)/2, \ + # -(bbox.YMin+bbox.YMax)/2 \ + # -(bbox.ZMin+bbox.ZMax)/2) + # print(base) + + # base = FreeCAD.Vector(0,0,0) + # fp.Shape = translate(solid,base) + fp.Shape = solid + fp.Placement = currPlacement + + +class GDMLTessellated(GDMLsolid): + + def __init__(self, obj, vertex, facets, flag, lunit, material, + colour=None): + super().__init__(obj) + # ######################################## + # if flag == True - facets is Mesh.Facets - with Normals + # if flag == False - facets is Faces i.e. from import GDMLTessellated + # ######################################## + obj.addProperty('App::PropertyInteger', 'facets', 'GDMLTessellated', + 'Facets').facets = len(facets) + obj.setEditorMode('facets', 1) + obj.addProperty('App::PropertyInteger', 'vertex', 'GDMLTessellated', + 'Vertex').vertex = len(vertex) + obj.setEditorMode('vertex', 1) + obj.addProperty("App::PropertyEnumeration", "lunit", + "GDMLTessellated", "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", + "GDMLTessellated", "Material") + setMaterial(obj, material) + self.updateParams(vertex, facets, flag) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + self.Type = 'GDMLTessellated' + self.colour = colour + obj.Proxy = self + + def updateParams(self, vertex, facets, flag): + # print('Update Params & Shape') + self.pshape = self.createShape(vertex, facets, flag) + # print(f"Pshape vertex {len(self.pshape.Vertexes)}") + self.facets = len(facets) + self.vertex = len(vertex) + # print(f"Vertex : {self.vertex} Facets : {self.facets}") + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['editable']: + if fp.editable is True: + self.addProperties() + + def addProperties(self): + print('Add Properties') + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + if hasattr(self, 'pshape'): + # print('Update Shape') + fp.Shape = self.pshape + if hasattr(fp, 'pshape'): + fp.pshape = self.pshape + fp.vertex = self.vertex + fp.facets = self.facets + + def createShape(self, vertex, facets, flag): + # Viewing outside of face vertex must be counter clockwise + # if flag == True - facets is Mesh.Facets + # if flag == False - factes is Faces i.e. from import GDMLTessellated + # mul = GDMLShared.getMult(fp) + mul = GDMLShared.getMult(self) + # print('Create Shape') + FCfaces = [] + for f in facets: + # print('Facet') + # print(f) + if flag is True: + FCfaces.append(GDMLShared.facet(f)) + else: + if len(f) == 3: + FCfaces.append(GDMLShared.triangle( + mul*vertex[f[0]], + mul*vertex[f[1]], + mul*vertex[f[2]])) + else: # len should then be 4 + FCfaces.append(GDMLShared.quad( + mul*vertex[f[0]], + mul*vertex[f[1]], + mul*vertex[f[2]], + mul*vertex[f[3]])) + shell = Part.makeShell(FCfaces) + if shell.isValid is False: + FreeCAD.Console.PrintWarning('Not a valid Shell/n') + + # shell.check() + # solid=Part.Solid(shell).removeSplitter() + try: + solid = Part.Solid(shell) + except: + # make compound rather than just barf + # visually able to view at least + FreeCAD.Console.PrintWarning('Problem making Solid/n') + solid = Part.makeCompound(FCfaces) + + return solid + + +class GDMLTetra(GDMLsolid): # 4 point Tetrahedron + + def __init__(self, obj, v1, v2, v3, v4, lunit, material, colour=None): + super().__init__(obj) + obj.addProperty("App::PropertyVector", "v1", "GDMLTra", + "v1").v1 = v1 + obj.addProperty("App::PropertyVector", "v2", "GDMLTra", + "v2").v2 = v2 + obj.addProperty("App::PropertyVector", "v3", "GDMLTra", + "v3").v3 = v3 + obj.addProperty("App::PropertyVector", "v4", "GDMLTra", + "v4").v4 = v4 + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLTra", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", + "GDMLTra", "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + self.Type = 'GDMLTetra' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['v1', 'v2', 'v3', 'v4', 'lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def createGeometry(self, fp): + currPlacement = fp.Placement + mul = GDMLShared.getMult(fp) + pt1 = mul * fp.v1 + pt2 = mul * fp.v2 + pt3 = mul * fp.v3 + pt4 = mul * fp.v4 + face1 = Part.Face(Part.makePolygon([pt1, pt2, pt3, pt1])) + face2 = Part.Face(Part.makePolygon([pt1, pt2, pt4, pt1])) + face3 = Part.Face(Part.makePolygon([pt4, pt2, pt3, pt4])) + face4 = Part.Face(Part.makePolygon([pt1, pt3, pt4, pt1])) + fp.Shape = Part.makeSolid(Part.makeShell([face1, face2, face3, face4])) + fp.Placement = currPlacement + + +class GDMLTetrahedron(GDMLsolid): + + ''' Does not exist as a GDML solid, but export as an Assembly of G4Tet ''' + ''' See paper Poole at al - Fast Tessellated solid navigation in GEANT4 ''' + + def __init__(self, obj, tetra, lunit, material, colour=None): + super().__init__(obj) + obj.addProperty('App::PropertyInteger', 'tetra', 'GDMLTetrahedron', + 'Tetra').tetra = len(tetra) + obj.setEditorMode('tetra', 1) + obj.addProperty("App::PropertyEnumeration", "lunit", "GDMLTetrahedron", + "lunit") + setLengthQuantity(obj, lunit) + obj.addProperty("App::PropertyEnumeration", "material", + "GDMLTetrahedron", "Material") + setMaterial(obj, material) + if FreeCAD.GuiUp: + updateColour(obj, colour, material) + # Suppress Placement - position & Rotation via parent App::Part + # this makes Placement via Phyvol easier and allows copies etc + # obj.addExtension('App::GroupExtensionPython') + self.Tetra = tetra + self.Object = obj + self.Type = 'GDMLTetrahedron' + self.colour = colour + obj.Proxy = self + + def onChanged(self, fp, prop): + '''Do something when a property has changed''' + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + if 'Restore' in fp.State: + return + + if prop in ['material']: + if FreeCAD.GuiUp: + if hasattr(self, 'colour'): + if self.colour is None: + fp.ViewObject.ShapeColor = colourMaterial(fp.material) + + if prop in ['lunit']: + self.createGeometry(fp) + + # def execute(self, fp): in GDMLsolid + + def makeTetra(self, pt1, pt2, pt3, pt4): + face1 = Part.Face(Part.makePolygon([pt1, pt2, pt3, pt1])) + face2 = Part.Face(Part.makePolygon([pt1, pt2, pt4, pt1])) + face3 = Part.Face(Part.makePolygon([pt4, pt2, pt3, pt4])) + face4 = Part.Face(Part.makePolygon([pt1, pt3, pt4, pt1])) + return(Part.makeShell([face1, face2, face3, face4])) + + def createGeometry(self, fp): + currPlacement = fp.Placement + print("Tetrahedron") + mul = GDMLShared.getMult(fp) + print(len(self.Tetra)) + tetraShells = [] + for t in self.Tetra: + pt1 = mul * t[0] + pt2 = mul * t[1] + pt3 = mul * t[2] + pt4 = mul * t[3] + tetraShells.append(self.makeTetra(pt1, pt2, pt3, pt4)) + fp.Shape = Part.makeCompound(tetraShells) + fp.Placement = currPlacement + + +class GDMLFiles(GDMLcommon): + def __init__(self, obj, FilesEntity, sectionDict): + super().__init__(obj) + '''Add some custom properties to our Cone feature''' + GDMLShared.trace("GDML Files") + GDMLShared.trace(FilesEntity) + obj.addProperty("App::PropertyBool", "active", "GDMLFiles", + "split option").active = FilesEntity + obj.addProperty("App::PropertyString", "define", "GDMLFiles", + "define section").define = sectionDict.get('define', "") + obj.addProperty("App::PropertyString", "materials", "GDMLFiles", + "materials section").materials = sectionDict.get('materials', "") + obj.addProperty("App::PropertyString", "solids", "GDMLFiles", + "solids section").solids = sectionDict.get('solids', "") + obj.addProperty("App::PropertyString", "structure", "GDMLFiles", + "structure section").structure = sectionDict.get('structure', "") + self.Type = 'GDMLFiles' + obj.Proxy = self + + def execute(self, fp): + '''Do something when doing a recomputation, this method is mandatory''' + pass + + def onChanged(self, fp, prop): + # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + # if not ('Restore' in fp.State) : + # if not hasattr(fp,'onchange') or not fp.onchange : return + pass + + +class GDMLvolume: + def __init__(self, obj): + obj.Proxy = self + self.Object = obj + + +class GDMLconstant(GDMLcommon): + def __init__(self, obj, name, value): + super().__init__(obj) + obj.addProperty("App::PropertyString", "name", 'GDMLconstant', + 'name').name = name + obj.addProperty("App::PropertyString", "value", 'GDMLconstant', + 'value').value = value + obj.Proxy = self + self.Object = obj + + +class GDMLvariable(GDMLcommon): + def __init__(self, obj, name, value): + super().__init__(obj) + obj.addProperty("App::PropertyString", "name", 'GDMLvariable', + 'name').name = name + obj.addProperty("App::PropertyString", "value", 'GDMLvariable', + 'value').value = value + obj.Proxy = self + self.Object = obj + + +class GDMLquantity(GDMLcommon): + def __init__(self, obj, name, type, unit, value): + super().__init__(obj) + obj.addProperty("App::PropertyString", "name", 'GDMLvariable', + 'name').name = name + obj.addProperty("App::PropertyString", "type", 'GDMLvariable', + 'type').type = type + obj.addProperty("App::PropertyString", "unit", 'GDMLvariable', + 'unit').unit = unit + obj.addProperty("App::PropertyString", "value", 'GDMLvariable', + 'value').value = value + obj.Proxy = self + self.Object = obj + + +class GDMLmaterial(GDMLcommon): + def __init__(self, obj, name, density=1.0, conduct=2.0, expand=3.0, + specific=4.0): + super().__init__(obj) + # Add most properties later + obj.addProperty("App::PropertyString", "name", 'GDMLmaterial', + 'name').name = name + obj.addProperty("App::PropertyFloat", "density", "GDMLmaterial", + "Density kg/m^3").density = density + obj.addProperty("App::PropertyFloat", "conduct", "GDMLmaterial", + "Thermal Conductivity W/m/K").conduct = conduct + obj.addProperty("App::PropertyFloat", "expand", "GDMLmaterial", + "Expansion Coefficient m/m/K").expand = expand + obj.addProperty("App::PropertyFloat", "specific", "GDMLmaterial", + "Specific Heat J/kg/K").specific = specific + + obj.Proxy = self + self.Object = obj + + +class GDMLfraction(GDMLcommon): + def __init__(self, obj, ref, n): + super().__init__(obj) + obj.addProperty("App::PropertyFloat", 'n', ref).n = n + obj.Proxy = self + self.Object = obj + + +class GDMLcomposite(GDMLcommon): + def __init__(self, obj, name, n, ref): + super().__init__(obj) + obj.addProperty("App::PropertyInteger", "n", name).n = n + obj.addProperty("App::PropertyString", "ref", name).ref = ref + obj.Proxy = self + self.Object = obj + + +class GDMLelement(GDMLcommon): + def __init__(self, obj, name): + super().__init__(obj) + obj.addProperty("App::PropertyString", "name", name).name = name + obj.Proxy = self + self.Object = obj + + +class GDMLisotope(GDMLcommon): + def __init__(self, obj, name, N, Z): + super().__init__(obj) + obj.addProperty("App::PropertyString", "name", name).name = name + obj.addProperty("App::PropertyInteger", "N", name).N = N + obj.addProperty("App::PropertyInteger", "Z", name).Z = Z + # Name, N and Z are minimum other values are added by import + # obj.addProperty("App::PropertyString","unit",name).unit = unit + # obj.addProperty("App::PropertyFloat","value",name).value = value + obj.Proxy = self + self.Object = obj + + +class ViewProviderExtension(GDMLcommon): + def __init__(self, obj): + super().__init__(obj) + obj.addExtension("Gui::ViewProviderGroupExtensionPython") + obj.Proxy = self + + def getDisplayModes(self, obj): + '''Return a list of display modes.''' + modes = [] + modes.append("Shaded") + modes.append("Wireframe") + return modes + + def updateData(self, fp, prop): + '''If a property of the handled feature has changed we have the chance to handle this here''' + # fp is the handled feature, prop is the name of the property that has changed + # l = fp.getPropertyByName("Length") + # w = fp.getPropertyByName("Width") + # h = fp.getPropertyByName("Height") + # self.scale.scaleFactor.setValue(float(l),float(w),float(h)) + pass + + def getDefaultDisplayMode(self): + '''Return the name of the default display mode. It must be defined in getDisplayModes.''' + return "Shaded" + # use general ViewProvider if poss class ViewProvider(GDMLcommon): - def __init__(self, obj): - super().__init__(obj) - '''Set this object to the proxy object of the actual view provider''' - obj.Proxy = self + def __init__(self, obj): + super().__init__(obj) + '''Set this object to the proxy object of the actual view provider''' + obj.Proxy = self + + def updateData(self, fp, prop): + '''If a property of the handled feature has changed we have the chance to handle this here''' + # print("updateData") + # fp is the handled feature, prop is the name of the property that has changed + # l = fp.getPropertyByName("Length") + # w = fp.getPropertyByName("Width") + # h = fp.getPropertyByName("Height") + # self.scale.scaleFactor.setValue(float(l),float(w),float(h)) + pass + + def getDisplayModes(self, obj): + '''Return a list of display modes.''' + # print("getDisplayModes") + modes = [] + modes.append("Shaded") + modes.append("Wireframe") + return modes - def updateData(self, fp, prop): - '''If a property of the handled feature has changed we have the chance to handle this here''' - #print("updateData") - # fp is the handled feature, prop is the name of the property that has changed - #l = fp.getPropertyByName("Length") - #w = fp.getPropertyByName("Width") - #h = fp.getPropertyByName("Height") - #self.scale.scaleFactor.setValue(float(l),float(w),float(h)) - pass + def getDefaultDisplayMode(self): + '''Return the name of the default display mode. It must be defined in getDisplayModes.''' + return "Shaded" - def getDisplayModes(self,obj): - '''Return a list of display modes.''' - #print("getDisplayModes") - modes=[] - modes.append("Shaded") - modes.append("Wireframe") - return modes - - def getDefaultDisplayMode(self): - '''Return the name of the default display mode. It must be defined in getDisplayModes.''' - return "Shaded" - - def setDisplayMode(self,mode): - '''Map the display mode defined in attach with those defined in getDisplayModes.\ + def setDisplayMode(self,mode): + '''Map the display mode defined in attach with those defined in getDisplayModes.\ Since they have the same names nothing needs to be done. This method is optional''' - return mode + return mode - def onChanged(self, vp, prop): - '''Here we can do something when a single property got changed''' - #if hasattr(vp,'Name') : - # print("View Provider : "+vp.Name+" State : "+str(vp.State)+" prop : "+prop) - #else : - # print("View Provider : prop : "+prop) - #GDMLShared.trace("Change property: " + str(prop) + "\n") - #if prop == "Color": - # c = vp.getPropertyByName("Color") -# self.color.rgb.setValue(c[0],c[1],c[2]) - - def getIcon(self): - '''Return the icon in XPM format which will appear in the tree view. This method is\ + def onChanged(self, vp, prop): + '''Here we can do something when a single property got changed''' + # if hasattr(vp,'Name') : + # print("View Provider : "+vp.Name+" State : "+str(vp.State)+" prop : "+prop) + # else : + # print("View Provider : prop : "+prop) + # GDMLShared.trace("Change property: " + str(prop) + "\n") + # if prop == "Color": + # c = vp.getPropertyByName("Color") + # self.color.rgb.setValue(c[0],c[1],c[2]) + + def getIcon(self): + '''Return the icon in XPM format which will appear in the tree view. This method is\ optional and if not defined a default icon is shown.''' - return """ + return """ /* XPM */ static const char * ViewProviderBox_xpm[] = { "16 16 6 1", @@ -3550,36 +3682,40 @@ def getIcon(self): " ##$$$$$# ", " ####### "}; """ - def __getstate__(self): - '''When saving the document this object gets stored using Python's json module.\ + + def __getstate__(self): + '''When saving the document this object gets stored using Python's json module.\ Since we have some un-serializable parts here -- the Coin stuff -- we must define this method\ to return a tuple of all serializable objects or None.''' - return None + return None - def __setstate__(self,state): - '''When restoring the serialized object from document we have the chance to set some internals here.\ + def __setstate__(self, state): + '''When restoring the serialized object from document we have the chance to set some internals here.\ Since no data were serialized nothing needs to be done here.''' - return None + return None # # Need to add variables to these functions or delete? # def makeBox(): - a=FreeCAD.ActiveDocument.addObject("App::FeaturePython","GDMLBox") + a = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "GDMLBox") GDMLBox(a) ViewProvider(a.ViewObject) + def makeCone(): - a=FreeCAD.ActiveDocument.addObject("App::FeaturePython","GDMLCone") + a = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "GDMLCone") GDMLCone(a) ViewProvider(a.ViewObject) + def makecSphere(): - a=FreeCAD.ActiveDocument.addObject("App::FeaturePython","GDMLSphere") + a = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "GDMLSphere") GDMLSphere(a) ViewProvider(a.ViewObject) + def makeTube(): - a=FreeCAD.ActiveDocument.addObject("App::FeaturePython","GDMLTube") + a = FreeCAD.ActiveDocument.addObject("App::FeaturePython", "GDMLTube") GDMLTube(a) ViewProvider(a.ViewObject) diff --git a/freecad/gdml/GDMLShared.py b/freecad/gdml/GDMLShared.py index 0fd5ba8ac..b6ddcab27 100644 --- a/freecad/gdml/GDMLShared.py +++ b/freecad/gdml/GDMLShared.py @@ -2,37 +2,37 @@ # single access to globals # anything requiring access to globals needs to call a function in this file # anything needing to call eval needs to be in this file -#************************************************************************** -#* * -#* Copyright (c) 2017 Keith Sloan * -#* (c) Dam Lambert 2020 * -#* * -#* 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 * -#* * -#* Acknowledgements : * -#* * -#* * -#************************************************************************** +# ************************************************************************** +# * * +# * Copyright (c) 2017 Keith Sloan * +# * (c) Dam Lambert 2020 * +# * * +# * 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 * +# * * +# * Acknowledgements : * +# * * +# * * +# ************************************************************************** from math import * import FreeCAD, Part from PySide import QtCore, QtGui -#from lxml import etree as ET +# from lxml import etree as ET global define global tracefp @@ -40,41 +40,46 @@ global printverbose printverbose = False -def setTrace(flag) : + +def setTrace(flag): global tracefp - print('Trace set to : '+str(flag)) + print('Trace set to : ' + str(flag)) global printverbose printverbose = flag - if flag == True : - tracePath = FreeCAD.getUserAppDataDir() - tracefp = open(tracePath+'FC-trace','w') - print('Trace path : '+tracePath) + if flag is True: + tracePath = FreeCAD.getUserAppDataDir() + tracefp = open(tracePath + 'FC-trace', 'w') + print('Trace path : ' + tracePath) + -def getTrace() : +def getTrace(): global printverbose - #print('Get Trace : '+str(printverbose)) + # print('Get Trace : '+str(printverbose)) return(printverbose) + def trace(s): global tracefp - if printverbose == True : - print(s) - print(s,file = tracefp) - tracefp.flush() + if printverbose is True: + print(s) + print(s, file=tracefp) + tracefp.flush() return + def errorDialog(msg, title='Warning', type=2): # Create a simple dialog QMessageBox # type indicates the icon used: one of QtGui.QMessageBox.{NoIcon, Information, Warning, Critical, Question} - typeDict = {0:QtGui.QMessageBox.NoIcon, \ - 1:QtGui.QMessageBox.Information, \ - 2:QtGui.QMessageBox.Warning, \ - 3:QtGui.QMessageBox.Critical, \ - 4:QtGui.QMessageBox.Question} - diag = QtGui.QMessageBox(Dict(type),title,msg) + typeDict = {0: QtGui.QMessageBox.NoIcon, + 1: QtGui.QMessageBox.Information, + 2: QtGui.QMessageBox.Warning, + 3: QtGui.QMessageBox.Critical, + 4: QtGui.QMessageBox.Question} + diag = QtGui.QMessageBox(Dict(type), title, msg) diag.setWindowModality(QtCore.Qt.ApplicationModal) diag.exec_() + def getFloatVal(expr): try: ret = float(eval(expr)) @@ -87,112 +92,115 @@ def getFloatVal(expr): ret = 0.0 print("Illegal float value: {}".format(expr)) return ret - -def setDefine(val) : - #print("Set Define") + +def setDefine(val): + # print("Set Define") global define define = val + def processConstants(doc): # all of math must be imported at global level - #setTrace(True) + # setTrace(True) trace("Process Constants") constantGrp = doc.getObject('Constants') - if constantGrp is None : - constantGrp = doc.addObject("App::DocumentObjectGroupPython","Constants") + if constantGrp is None: + constantGrp = doc.addObject("App::DocumentObjectGroupPython", + "Constants") from .GDMLObjects import GDMLconstant - for cdefine in define.findall('constant') : - #print cdefine.attrib - name = str(cdefine.attrib.get('name')) - trace('name : '+name) + for cdefine in define.findall('constant'): + # print cdefine.attrib + name = str(cdefine.attrib.get('name')) + trace('name : ' + name) value = cdefine.attrib.get('value') - trace('value : '+ value) - #constDict[name] = value - #trace(name) - #print(dir(name)) - try : - globals()[name] = eval(value) - except : # eg 5*cm - globals()[name] = value - constObj = constantGrp.newObject("App::DocumentObjectGroupPython", \ - name) - GDMLconstant(constObj,name,value) - - #print("Globals") - #print(str(globals())) + trace('value : ' + value) + # constDict[name] = value + # trace(name) + # print(dir(name)) + try: + globals()[name] = eval(value) + except: # eg 5*cm + globals()[name] = value + constObj = constantGrp.newObject("App::DocumentObjectGroupPython", + name) + GDMLconstant(constObj, name, value) + + # print("Globals") + # print(str(globals())) + def processVariables(doc): # all of math must be imported at global level trace("Process Variables") variablesGrp = doc.getObject('Variables') - if variablesGrp is None : - variablesGrp = doc.addObject("App::DocumentObjectGroupPython","Variables") + if variablesGrp is None: + variablesGrp = doc.addObject("App::DocumentObjectGroupPython", + "Variables") from .GDMLObjects import GDMLconstant from .GDMLObjects import GDMLvariable - #import math - - #globals()['sin'] = math.sin - #globals()['cos'] = math.cos globals()['false'] = False globals()['true'] = True - for cdefine in define.findall('variable') : - #print cdefine.attrib - name = str(cdefine.attrib.get('name')) + for cdefine in define.findall('variable'): + # print cdefine.attrib + name = str(cdefine.attrib.get('name')) trace('name : '+name) value = cdefine.attrib.get('value') - trace('value : '+ value) - #constDict[name] = value + trace('value : ' + value) + # constDict[name] = value trace(name) - #print(dir(name)) - #print('Name : '+name) - try : - globals()[name] = eval(value) - #print('Value : '+value) - except : - globals()[name] = value - #print('Value String : '+value) - variableObj = variablesGrp.newObject("App::DocumentObjectGroupPython", \ - name) - GDMLvariable(variableObj,name,value) - #print("Globals") - #print(str(globals())) + # print(dir(name)) + # print('Name : '+name) + try: + globals()[name] = eval(value) + # print('Value : '+value) + except: + globals()[name] = value + # print('Value String : '+value) + variableObj = variablesGrp.newObject("App::DocumentObjectGroupPython", + name) + GDMLvariable(variableObj, name, value) + # print("Globals") + # print(str(globals())) + def processQuantities(doc): # all of math must be imported at global level trace("Process Quantitities") quantityGrp = doc.getObject('Quantities') - if quantityGrp is None : - quantityGrp = doc.addObject("App::DocumentObjectGroupPython","Quantities") + if quantityGrp is None: + quantityGrp = doc.addObject("App::DocumentObjectGroupPython", + "Quantities") from .GDMLObjects import GDMLquantity - for cdefine in define.findall('quantity') : - #print cdefine.attrib - name = str(cdefine.attrib.get('name')) + for cdefine in define.findall('quantity'): + # print cdefine.attrib + name = str(cdefine.attrib.get('name')) trace('name : '+name) type = cdefine.attrib.get('type') - trace('type : '+ type) + trace('type : ' + type) unit = cdefine.attrib.get('unit') - trace('unit : '+ unit) + trace('unit : ' + unit) value = cdefine.attrib.get('value') - trace('value : '+ value) - #constDict[name] = value + trace('value : ' + value) + # constDict[name] = value trace(name) - #print(dir(name)) - #print('Name : '+name) - try : - globals()[name] = eval(value) - #print('Value : '+value) - except : - globals()[name] = value - #print('Value String : '+value) - quantityObj = quantityGrp.newObject("App::DocumentObjectGroupPython", \ - name) - GDMLquantity(quantityObj,name,type,unit,value) - #print("Globals") - #print(str(globals())) + # print(dir(name)) + # print('Name : '+name) + try: + globals()[name] = eval(value) + # print('Value : '+value) + except: + globals()[name] = value + # print('Value String : '+value) + quantityObj = quantityGrp.newObject("App::DocumentObjectGroupPython", + name) + GDMLquantity(quantityObj, name, type, unit, value) + # print("Globals") + # print(str(globals())) + def processPositions(doc): print('Process Positions') @@ -218,191 +226,198 @@ def processPositions(doc): else: z = 0 - positions[atts['name']] = {'unit': unit, \ + positions[atts['name']] = {'unit': unit, 'x': x, 'y': y, 'z': z} trace("Positions processed") + def processExpression(doc): # need to be done ? trace("Expressions Not processed & Displayed") + def processRotation(doc): # need to be done ? trace("Rotations Not processed & Displayed") -def getVal(ptr,var,default=0) : + +def getVal(ptr, var, default=0): # all of math must be imported at global level - #print ptr.attrib + # print ptr.attrib # is the variable defined in passed attribute - if var in ptr.attrib : - # if yes get its value - vval = ptr.attrib.get(var) - trace(var+" : "+str(vval)) - if vval[0] == '&' : # Is this referring to an HTML entity constant - chkval = vval[1:] - else : - chkval = vval - trace("chkval : "+str(chkval)) - try: - ret = float(eval(chkval)) - except: - try: - ret = float(chkval) - except: - print("Illegal float: {}" % chkval) - ret = 0.0 - - trace('return value : '+str(ret)) - return(ret) + if var in ptr.attrib: + # if yes get its value + vval = ptr.attrib.get(var) + trace(var + " : " + str(vval)) + if vval[0] == '&': # Is this referring to an HTML entity constant + chkval = vval[1:] + else: + chkval = vval + trace("chkval : " + str(chkval)) + try: + ret = float(eval(chkval)) + except: + try: + ret = float(chkval) + except: + print("Illegal float: {}" % chkval) + ret = 0.0 + + trace('return value : ' + str(ret)) + return(ret) return default # get ref e.g name world, solidref, materialref -def getRef(ptr, name) : + + +def getRef(ptr, name): wrk = ptr.find(name) - if wrk is not None : - ref = wrk.get('ref') - trace(name + ' : ' + ref) - return ref + if wrk is not None: + ref = wrk.get('ref') + trace(name + ' : ' + ref) + return ref return wrk -def getMult(fp) : - unit = 'mm' # set default + +def getMult(fp): + unit = 'mm' # set default # Watch for unit and lunit - #print('getMult : '+str(fp)) - if hasattr(fp,'lunit') : + # print('getMult : '+str(fp)) + if hasattr(fp, 'lunit'): trace('lunit : '+fp.lunit) unit = fp.lunit - elif hasattr(fp,'unit') : - trace('unit : '+fp.unit) + elif hasattr(fp, 'unit'): + trace('unit : ' + fp.unit) unit = fp.unit - elif hasattr(fp,'attrib') : - if 'unit' in fp.attrib : - unit = fp.attrib['unit'] - elif 'lunit' in fp.attrib : - unit = fp.attrib['lunit'] - else : + elif hasattr(fp, 'attrib'): + if 'unit' in fp.attrib: + unit = fp.attrib['unit'] + elif 'lunit' in fp.attrib: + unit = fp.attrib['lunit'] + else: return 1 - if unit == 'mm' : return(1) - elif unit == 'cm' : return(10) - elif unit == 'm' : return(1000) - elif unit == 'um' : return(0.001) - elif unit == 'nm' : return(0.000001) - elif unit == 'dm' : return(100) - elif unit == 'm' : return(1000) - elif unit == 'km' : return(1000000) - print('unit not handled : '+unit) - -def getDegrees(flag, r) : + + unitsDict = {'mm': 1, 'cm': 10, 'm': 1000, 'um': 0.001, 'nm': 0.000001, + 'dm': 100, 'm': 1000, 'km': 1000000} + if unit in unitsDict: + return unitsDict[unit] + + print('unit not handled : ' + unit) + + +def getDegrees(flag, r): import math - if flag == True : - return r * 180/math.pi - else : - return r + if flag is True: + return r * 180/math.pi + else: + return r + -def getRadians(flag,r) : +def getRadians(flag, r): import math - if flag == True : + if flag is True: return r - else : + else: return r * math.pi / 180 -def processPlacement(base,rot) : - #setTrace(True) - #trace('processPlacement') + +def processPlacement(base, rot): + # setTrace(True) + # trace('processPlacement') # Different Objects will have adjusted base GDML-FreeCAD - # rot is rotation or None if default + # rot is rotation or None if default # set rotation matrix - #print('process Placement : '+str(base)) - if rot is None : - return FreeCAD.Placement(base,FreeCAD.Rotation(0,0,0,1)) - - else : + # print('process Placement : '+str(base)) + if rot is None: + return FreeCAD.Placement(base, FreeCAD.Rotation(0, 0, 0, 1)) + + else: trace("Rotation : ") trace(rot.attrib) x = y = z = 0 - if 'name' in rot.attrib : - if rot.attrib['name'] == 'identity' : + if 'name' in rot.attrib: + if rot.attrib['name'] == 'identity': trace('identity') - return FreeCAD.Placement(base,FreeCAD.Rotation(0,0,0,1)) + return FreeCAD.Placement(base, FreeCAD.Rotation(0, 0, 0, 1)) radianFlg = True - if 'unit' in rot.attrib : - #print(rot.attrib['unit'][:3]) - if rot.attrib['unit'][:3] == 'deg' : + if 'unit' in rot.attrib: + # print(rot.attrib['unit'][:3]) + if rot.attrib['unit'][:3] == 'deg': radianFlg = False - if 'x' in rot.attrib : - trace('x : '+rot.attrib['x']) - #print(eval('HALFPI')) + if 'x' in rot.attrib: + trace('x : ' + rot.attrib['x']) + # print(eval('HALFPI')) trace(eval(rot.attrib['x'])) - x = getDegrees(radianFlg,float(eval(rot.attrib['x']))) - trace('x deg : '+str(x)) - - if 'y' in rot.attrib : - trace('y : '+rot.attrib['y']) - y = getDegrees(radianFlg,float(eval(rot.attrib['y']))) - trace('y deg : '+str(y)) - - if 'z' in rot.attrib : + x = getDegrees(radianFlg, float(eval(rot.attrib['x']))) + trace('x deg : ' + str(x)) + + if 'y' in rot.attrib: + trace('y : ' + rot.attrib['y']) + y = getDegrees(radianFlg, float(eval(rot.attrib['y']))) + trace('y deg : ' + str(y)) + + if 'z' in rot.attrib: trace('z : '+rot.attrib['z']) - z = getDegrees(radianFlg,float(eval(rot.attrib['z']))) - trace('z deg : '+str(z)) - - rotX = FreeCAD.Rotation(FreeCAD.Vector(1,0,0), -x) - rotY = FreeCAD.Rotation(FreeCAD.Vector(0,1,0), -y) - rotZ = FreeCAD.Rotation(FreeCAD.Vector(0,0,1), -z) - - rot = rotX.multiply(rotY).multiply(rotZ) - #rot = rotX - #c_rot = FreeCAD.Vector(0,0,0) # Center of rotation - #print('base : '+str(base)) - #print('rot : '+str(rot)) - #return FreeCAD.Placement(base, rot, c_rot) - - #placement = FreeCAD.Placement(base, FreeCAD.Rotation(-x,-y,-z)) - #placement = FreeCAD.Placement(base, FreeCAD.Rotation(-z,-y,-x), \ + z = getDegrees(radianFlg, float(eval(rot.attrib['z']))) + trace('z deg : ' + str(z)) + + rotX = FreeCAD.Rotation(FreeCAD.Vector(1, 0, 0), -x) + rotY = FreeCAD.Rotation(FreeCAD.Vector(0, 1, 0), -y) + rotZ = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), -z) + + rot = rotZ*rotY*rotX + # rot = rotX.multiply(rotY).multiply(rotZ) + # rot = rotX + # c_rot = FreeCAD.Vector(0,0,0) # Center of rotation + # print('base : '+str(base)) + # print('rot : '+str(rot)) + # return FreeCAD.Placement(base, rot, c_rot) + + # placement = FreeCAD.Placement(base, FreeCAD.Rotation(-x,-y,-z)) + # placement = FreeCAD.Placement(base, FreeCAD.Rotation(-z,-y,-x), \ # base) placement = FreeCAD.Placement(base, FreeCAD.Rotation(rot)) - #print('placement : '+str(placement)) + # print('placement : '+str(placement)) return placement -def getPositionFromAttrib(pos) : - #print('getPositionFromAttrib') - #print('pos : '+str(ET.tostring(pos))) - #print(pos.attrib) - #if hasattr(pos.attrib, 'unit') : # Note unit NOT lunit - #if hasattr(pos.attrib,'name') : + +def getPositionFromAttrib(pos): + # print('getPositionFromAttrib') + # print('pos : '+str(ET.tostring(pos))) + # print(pos.attrib) + # if hasattr(pos.attrib, 'unit') : # Note unit NOT lunit + # if hasattr(pos.attrib,'name') : # name = pos.get('name') # if name == 'center' : # return(0,0,0) mul = getMult(pos) - px = mul * getVal(pos,'x') - py = mul * getVal(pos,'y') - pz = mul * getVal(pos,'z') - return px, py, pz - -def getPositionFromDict(pos) : - #print('getPositionFromAttrib') - #print('pos : '+str(ET.tostring(pos))) - #print(pos.attrib) - #if hasattr(pos.attrib, 'unit') : # Note unit NOT lunit - #if hasattr(pos.attrib,'name') : + px = mul * getVal(pos, 'x') + py = mul * getVal(pos, 'y') + pz = mul * getVal(pos, 'z') + return px, py, pz + + +def getPositionFromDict(pos): + # print('getPositionFromAttrib') + # print('pos : '+str(ET.tostring(pos))) + # print(pos.attrib) + # if hasattr(pos.attrib, 'unit') : # Note unit NOT lunit + # if hasattr(pos.attrib,'name') : # name = pos.get('name') # if name == 'center' : # return(0,0,0) unit = pos['unit'] mul = 1 - #mul = getMult(pos) - if unit == 'mm' : mul = 1 - elif unit == 'cm' : mul = 10 - elif unit == 'm' : mul = 1000 - elif unit == 'um' : mul = 0.001 - elif unit == 'nm' : mul = 0.000001 - elif unit == 'dm' : mul = 100 - elif unit == 'm' : mul = 1000 - elif unit == 'km' : mul = 1000000 + + unitsDict = {'mm': 1, 'cm': 10, 'm': 1000, 'um': 0.001, 'nm': 0.000001, + 'dm': 100, 'm': 1000, 'km': 1000000} + + if unit in unitsDict: + mul = unitsDict[unit] try: px = mul * float(pos['x']) @@ -410,150 +425,163 @@ def getPositionFromDict(pos) : pz = mul * float(pos['z']) except: px = py = pz = 0 - - return px, py, pz -# Return x,y,z from position definition -def getElementPosition(xmlElem) : - # get Position from local element - #setTrace(True) + return px, py, pz + + +# Return x,y,z from position definition +def getElementPosition(xmlElem): + # get Position from local element + # setTrace(True) trace("Get Element Position : ") pos = xmlElem.find("position") - if pos is not None : + if pos is not None: trace(pos.attrib) return(getPositionFromAttrib(pos)) - else : - return 0,0,0 + else: + return 0, 0, 0 -def getDefinedPosition(name) : - # get Position from define section - #pos = define.find("position[@name='%s']" % name ) + +def getDefinedPosition(name): + # get Position from define section + # pos = define.find("position[@name='%s']" % name ) pos = positions[name] - if pos is not None : - #print('Position : '+str(pos)) + if pos is not None: + # print('Position : '+str(pos)) trace(pos) - #return(getPositionFromAttrib(pos)) + # return(getPositionFromAttrib(pos)) return(getPositionFromDict(pos)) - else : - return 0,0,0 + else: + return 0, 0, 0 + -def getPosition(xmlEntity) : +def getPosition(xmlEntity): # Get position via reference - #setTrace(True) + # setTrace(True) trace('GetPosition via Reference if any') - posName = getRef(xmlEntity,"positionref") - if posName is not None : - trace("positionref : "+posName) - return(getDefinedPosition(posName)) - else : - return(getElementPosition(xmlEntity)) - -def testPosition(xmlEntity,px,py,pz) : - posName = getRef(xmlEntity,"positionref") - if posName is not None : - trace("positionref : "+posName) - return(getDefinedPosition(posName)) + posName = getRef(xmlEntity, "positionref") + if posName is not None: + trace("positionref : " + posName) + return(getDefinedPosition(posName)) + else: + return(getElementPosition(xmlEntity)) + + +def testPosition(xmlEntity, px, py, pz): + posName = getRef(xmlEntity, "positionref") + if posName is not None: + trace("positionref : " + posName) + return(getDefinedPosition(posName)) pos = xmlEntity.find("position") - if pos is not None : + if pos is not None: trace(pos.attrib) return(getPositionFromAttrib(pos)) - else : - return px,py,pz + else: + return px, py, pz -def getDefinedRotation(name) : + +def getDefinedRotation(name): # Just get definition - used by parseMultiUnion passed to create solids - return(define.find("rotation[@name='%s']" % name )) + return(define.find("rotation[@name='%s']" % name)) + -def getRotation(xmlEntity) : +def getRotation(xmlEntity): trace('GetRotation') - rotref = getRef(xmlEntity,"rotationref") - trace('rotref : '+str(rotref)) - if rotref is not None : - rot = define.find("rotation[@name='%s']" % rotref ) - else : - rot = xmlEntity.find("rotation") - if rot is not None : - trace(rot.attrib) + rotref = getRef(xmlEntity, "rotationref") + trace('rotref : ' + str(rotref)) + if rotref is not None: + rot = define.find("rotation[@name='%s']" % rotref) + else: + rot = xmlEntity.find("rotation") + if rot is not None: + trace(rot.attrib) return rot -def getRotFromRefs(ptr) : + +def getRotFromRefs(ptr): printverbose = True trace("getRotFromRef") - rot = define.find("rotation[@name='%s']" % getRef(ptr,'rotationref')) - if rot is not None : + rot = define.find("rotation[@name='%s']" % getRef(ptr, 'rotationref')) + if rot is not None: trace(rot.attrib) return rot -def getDefinedVector(solid, v) : + +def getDefinedVector(solid, v): global define - #print('get Defined Vector : '+v) + # print('get Defined Vector : '+v) name = solid.get(v) pos = define.find("position[@name='%s']" % name) - #print(pos.attrib) - x = getVal(pos,'x') - y = getVal(pos,'y') - z = getVal(pos,'z') - return(FreeCAD.Vector(x,y,z)) + # print(pos.attrib) + x = getVal(pos, 'x') + y = getVal(pos, 'y') + z = getVal(pos, 'z') + return(FreeCAD.Vector(x, y, z)) + -def getPlacement(pvXML) : +def getPlacement(pvXML): base = FreeCAD.Vector(getPosition(pvXML)) - #print('base: '+str(base)) - rot = getRotation(pvXML) - return(processPlacement(base,rot)) + # print('base: '+str(base)) + rot = getRotation(pvXML) + return(processPlacement(base, rot)) -def getScale(pvXML) : - #print(ET.tostring(pvXML)) + +def getScale(pvXML): + # print(ET.tostring(pvXML)) scale = pvXML.find('scale') x = y = z = 1. - if scale is not None : - #print(ET.tostring(scale)) - x = getVal(scale,'x') - y = getVal(scale,'y') - z = getVal(scale,'z') - return(FreeCAD.Vector(x,y,z)) + if scale is not None: + # print(ET.tostring(scale)) + x = getVal(scale, 'x') + y = getVal(scale, 'y') + z = getVal(scale, 'z') + return(FreeCAD.Vector(x, y, z)) + def getVertex(v): global define trace("Vertex") - #print(dir(v)) + # print(dir(v)) pos = define.find("position[@name='%s']" % v) - #print("Position") - #print(dir(pos)) - x = getVal(pos,'x') - trace('x : '+str(x)) - y = getVal(pos,'y') - trace('y : '+str(y)) - z = getVal(pos,'z') - trace('z : '+str(z)) - return(FreeCAD.Vector(x,y,z)) - -def facet(f) : - #vec = FreeCAD.Vector(1.0,1.0,1.0) - #print(f"Facet {f}") - #print(f.Points) - if len(f.Points) == 3 : - return(triangle(f.Points[0],f.Points[1],f.Points[2])) - #if f.Normal.dot(vec) > 0 : - # return(triangle(f.Points[0],f.Points[1],f.Points[2])) - #else : - # return(triangle(f.Points[2],f.Points[1],f.Points[0])) - else : - return(quad(f.Points[0],f.Points[1],f.Points[2],f.Points[3])) - #if f.Normal.dot(vec) > 0 : - # return(quad(f.Points[0],f.Points[1],f.Points[2],f.Points[3])) - #else : - # return(quad(f.Points[3],f.Points[2],f.Points[1],f.Points[0])) - - -def triangle(v1,v2,v3) : + # print("Position") + # print(dir(pos)) + x = getVal(pos, 'x') + trace('x : ' + str(x)) + y = getVal(pos, 'y') + trace('y : ' + str(y)) + z = getVal(pos, 'z') + trace('z : ' + str(z)) + return(FreeCAD.Vector(x, y, z)) + + +def facet(f): + # vec = FreeCAD.Vector(1.0,1.0,1.0) + # print(f"Facet {f}") + # print(f.Points) + if len(f.Points) == 3: + return(triangle(f.Points[0], f.Points[1], f.Points[2])) + # if f.Normal.dot(vec) > 0 : + # return(triangle(f.Points[0],f.Points[1],f.Points[2])) + # else : + # return(triangle(f.Points[2],f.Points[1],f.Points[0])) + else: + return(quad(f.Points[0], f.Points[1], f.Points[2], f.Points[3])) + # if f.Normal.dot(vec) > 0 : + # return(quad(f.Points[0],f.Points[1],f.Points[2],f.Points[3])) + # else : + # return(quad(f.Points[3],f.Points[2],f.Points[1],f.Points[0])) + + +def triangle(v1, v2, v3): # passed vertex return face - #print('v1 : '+str(v1)+' v2 : '+str(v2)+' v3 : '+str(v3)) - w1 = Part.makePolygon([v1,v2,v3,v1]) + # print('v1 : '+str(v1)+' v2 : '+str(v2)+' v3 : '+str(v3)) + w1 = Part.makePolygon([v1, v2, v3, v1]) f1 = Part.Face(w1) return(f1) -def quad(v1,v2,v3,v4) : + +def quad(v1, v2, v3, v4): # passed vertex return face - w1 = Part.makePolygon([v1,v2,v3,v4,v1]) + w1 = Part.makePolygon([v1, v2, v3, v4, v1]) f1 = Part.Face(w1) return(f1) diff --git a/freecad/gdml/exportExtrusion.py b/freecad/gdml/exportExtrusion.py new file mode 100644 index 000000000..05a4f17a2 --- /dev/null +++ b/freecad/gdml/exportExtrusion.py @@ -0,0 +1,845 @@ +# -*- mode: Python; python-indent-offset: 4; python-guess-indent: nil -*- +# Mon Dec 6 08:49:56 AM PST 2021 +# **************************************************************************pp +# * * +# * Copyright (c) 2019 Keith Sloan * +# * (c) 2020 Dam Lambert * +# * (c) 2021 Munther Hindi +# * +# * 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 * +# * * +# * Acknowledgements : Ideas & code copied from * +# * https://github.com/ignamv/geanTipi * +# * * +# *************************************************************************** +__title__ = "FreeCAD - GDML Extrude exporter Version" +__author__ = "Keith Sloan " +__url__ = ["https://github.com/KeithSloan/FreeCAD_Geant4"] + +import FreeCAD, Part, math +from FreeCAD import Vector +from .GDMLObjects import GDMLcommon, GDMLBox, GDMLTube + +# modif add +# from .GDMLObjects import getMult, convertionlisteCharToLunit + +import sys +try: + import lxml.etree as ET + FreeCAD.Console.PrintMessage("running with lxml.etree\n") + XML_IO_VERSION = 'lxml' +except ImportError: + try: + import xml.etree.ElementTree as ET + FreeCAD.Console.PrintMessage("running with xml.etree.ElementTree\n") + XML_IO_VERSION = 'xml' + except ImportError: + FreeCAD.Console.PrintMessage('pb xml lib not found\n') + sys.exit() +# xml handling +# import argparse +# from xml.etree.ElementTree import XML +################################# + +# *************************************************************************** +# Tailor following to your requirements ( Should all be strings ) * +# no doubt there will be a problem when they do implement Value +if open.__module__ in ['__builtin__', 'io']: + pythonopen = open # to distinguish python built-in open function from the one declared here + +# ## modifs lambda + + +def verifNameUnique(name): + # need to be done!! + return True + +# ## end modifs lambda + +################################# +# Switch functions +################################ + + +class switch(object): + value = None + + def __new__(class_, value): + class_.value = value + return True + + +def case(*args): + return any((arg == switch.value for arg in args)) + +############################################# +# Helper functions for extrude construction + +# One of the closed curves (list of edges) representing a part +# of the sketch + + +class ClosedCurve: + def __init__(self, name, edgeList): + self.name = name + self.face = Part.Face(Part.Wire(edgeList)) + self.edgeList = edgeList + + def isInside(self, otherCurve): + # ClosedCurves are closed: so if ANY vertex of the otherCurve + # is inside, then the whole curve is inside + return self.face.isInside(otherCurve.edgeList[0].Vertexes[0].Point, 0.001, True) + + +class ExtrudedClosedCurve(ClosedCurve): + def __init__(self, name, edgelist, height): + super().__init__(name, edgelist) + self.height = height + self.position = Vector(0, 0, 0) + self.rotation = [0, 0, 0] # TBD + + def export(self): + print('export not implemented') + + +class ExtrudedCircle(ExtrudedClosedCurve): + def __init__(self, name, edgelist, height): + super().__init__(name, edgelist, height) + self.position = edgelist[0].Curve.Center + Vector(0, 0, height/2) + + def export(self): + edge = self.edgeList[0] + exportTube(self.name, edge.Curve.Radius, self.height) + + +class ExtrudedArcSection(ExtrudedClosedCurve): + def __init__(self, name, edgelist, height): + super().__init__(name, edgelist, height) + # Note extrusion polyogn will be in absolute coordinates + # since arc section is relative to that, position is actually (0,0,0) + # same goes for rotation + + # return midpoint of arc, relative to center + def midPoint(self): + edge = self.edgeList[0] + radius = edge.Curve.Radius + thetmid = (edge.FirstParameter+edge.LastParameter)/2 + arcAngle = edge.LastParameter - edge.FirstParameter + v0 = edge.Vertexes[0].Point + v1 = edge.Vertexes[1].Point + vc = (v0+v1)/2 # chord center + vc_vcenter = vc - edge.Curve.Center + if vc_vcenter.Length < 0.001: # arc chord = diameter + # Although it seems that this should always work, I've seen cases in which + # each of the first, last parameters were shifter by pi and thetmid + # was off by pi + vmid = edge.Curve.Center + radius*Vector(math.cos(thetmid), math.sin(thetmid), 0) + else: + u_vc_vcenter = vc_vcenter.normalize() # unit vector fom center of circle to center of chord + if arcAngle < math.pi: # shorter of two arc segments, mid point and center are on opposite side + vmid = edge.Curve.Center + edge.Curve.Radius*u_vc_vcenter + else: #longer of two arc segments: midpoint is on opposite side of chord + vmid = edge.Curve.Center - edge.Curve.Radius*u_vc_vcenter + + return vmid + + def export(self): + global solids + from .exportGDML import exportPosition + + edge = self.edgeList[0] + radius = edge.Curve.Radius + # First form a bounding rectangle (polygon) for the arc. + # Arc edges + v1 = edge.Vertexes[0].Point + v2 = edge.Vertexes[1].Point + vmid = self.midPoint() + + # midpoint of chord + vc = (v1+v2)/2 + v = v2-v1 + u = v.normalize() + # extend the ends of the chord so extrusion can cut all of circle, if needed + v1 = vc + radius*u + v2 = vc - radius*u + # component of vmid perpendicular to u + vc_vmid = vmid - vc + n = vc_vmid - u.dot(vc_vmid)*u + n.normalize() + # complete edges of box paerpendicular to chord, toward mid arc point + v3 = v2 + 2*radius*n + v4 = v1 + 2*radius*n + + xtruName = self.name+'_xtru' + exportXtru(xtruName, [v1, v2, v3, v4], self.height) + + # tube to be cut1 + tubeName = self.name+'_tube' + exportTube(tubeName, edge.Curve.Radius, self.height) + + # note, it is mandatory that name be that of ClosedCurve + intersect = ET.SubElement(solids, 'intersection', {'name': self.name}) + ET.SubElement(intersect, 'first', {'ref': xtruName}) + ET.SubElement(intersect, 'second', {'ref': tubeName}) + pos = edge.Curve.Center + Vector(0, 0, self.height/2) + exportPosition(tubeName, intersect, pos) + + +class ExtrudedEllipse(ExtrudedClosedCurve): + def __init__(self, name, edgelist, height): + super().__init__(name, edgelist, height) + curve = edgelist[0].Curve + self.position = curve.Center + Vector(0, 0, height/2) + angle = math.degrees(curve.AngleXU) + self.rotation = [0, 0, angle] + + def export(self): + edge = self.edgeList[0] + exportEllipticalTube(self.name, edge.Curve.MajorRadius, + edge.Curve.MinorRadius, + self.height) + + +class ExtrudedEllipticalSection(ExtrudedClosedCurve): + def __init__(self, name, edgelist, height): + super().__init__(name, edgelist, height) + # Note extrusion polyogn will be in absolute coordinates + # since arc section is relative to that, position is actually (0,0,0) + # same goes for rotation + + def midPoint(self): + edge = self.edgeList[0] + a = edge.Curve.MajorRadius + b = edge.Curve.MinorRadius + angleXU = edge.Curve.AngleXU + thet1 = edge.FirstParameter # in radians, in unorated ellipse + thet2 = edge.LastParameter # in radians, in onrated ellipse + thetmid = (thet1+thet2)/2 + angleXU + + # Major axis angle seems to be off by pi for some ellipse. Restrict it to be + # be between 0 an pi + if angleXU < 0: + angleXU += 180 + v0 = edge.Vertexes[0].Point + v1 = edge.Vertexes[1].Point + + # TODO must deal with case where cutting chord is along major axis + # u_vc_vcenter = vc_vcenter.normalize() # unit vector fom center of circle to center of chord + + # vertexes of triangle formed by chord ends and ellise mid point + # In polar coordinates equation of ellipse is r(thet) = a*(1-eps*eps)/(1+eps*cos(thet)) + # if the ellipse is rotatated by an angle AngleXU, then + # x = r*cos(thet+angleXU), y = r*sin(thet+angleXU), for thet in frame of unrotated ellipse + # now edge.FirstParameter is begining angle of unrotaeted ellipse + + def sqr(x): + return x*x + + def r(thet): + return math.sqrt(1.0/(sqr(math.cos(thet)/a) + sqr(math.sin(thet)/b))) + + rmid = r(thetmid) + vmid = Vector(rmid*math.cos(thetmid), rmid*math.sin(thetmid), 0) + + vmid += edge.Curve.Center + + ''' + uxaxis = Vector(math.cos(angleXU), math.sin(angleXU), 0) + costhet = uxaxis.dot(u_vc_vcenter) # angle between major axis and center of chor + sinthet = math.sqrt(1-costhet*costhet) + # polar equation of ellipse, with r measured from FOCUS. Focus at a*eps + # r = lambda thet: a*(1-eps*eps)/(1+eps*math.cos(thet)) + # polar equation of ellipse, with r measured from center a*eps + sqr = lambda x: x*x + rmid = math.sqrt(1.0/(sqr(costhet/a) + sqr(sinthet/b))) + if arcAngle < math.pi: # shorter of two arc segments, mid point and center are on opposite side + vmid = edge.Curve.Center + rmid*u_vc_vcenter + else: #longer of two arc segments: midpoint is on opposite side of chord + vmid = edge.Curve.Center - rmid*u_vc_vcenter + ''' + + return vmid + + def export(self): + global solids + from .exportGDML import exportPosition + + edge = self.edgeList[0] + a = dx = edge.Curve.MajorRadius + b = dy = edge.Curve.MinorRadius + + # vertexes of triangle formed by chord ends and ellise mid point + # In polar coordinates equation of ellipse is r(thet) = a*(1-eps*eps)/(1+eps*cos(thet)) + # if the ellipse is rotatated by an angle AngleXU, then + # x = r*cos(thet+angleXU), y = r*sin(thet+angleXU), for thet in frame of unrotated ellipse + # now edge.FirstParameter is begining angle of unrotaeted ellipse + # polar equation of ellipse, with r measured from FOCUS. Focus at a*eps + # r = lambda thet: a*(1-eps*eps)/(1+eps*math.cos(thet)) + # polar equation of ellipse, with r measured from center a*eps + + def sqr(x): + return x*x + + def r(thet): + return math.sqrt(1.0/(sqr(math.cos(thet)/a) + sqr(math.sin(thet)/b))) + + v1 = edge.Vertexes[0].Point + v2 = edge.Vertexes[1].Point + vmid = self.midPoint() + + # midpoint of chord + vc = (v1+v2)/2 + v = v2-v1 + u = v.normalize() # unit vector from v1 to v2 + # extend the ends of the chord so extrusion can cut all of ellipse, if needed + v1 = vc + 2*a*u + v2 = vc - 2*a*u + + # component of vmid perpendicular to u + vc_vmid = vmid - vc + n = vc_vmid - u.dot(vc_vmid)*u + n.normalize() + v3 = v2 + 2*a*n + v4 = v1 + 2*a*n + + xtruName = self.name+'_xtru' + exportXtru(xtruName, [v1, v2, v3, v4], self.height) + + # tube to be cut1 + tubeName = self.name+'_tube' + exportEllipticalTube(tubeName, dx, dy, self.height) + + # note, it is mandatory that name be that of ClosedCurve + intersect = ET.SubElement(solids, 'intersection', {'name': self.name}) + ET.SubElement(intersect, 'first', {'ref': xtruName}) + ET.SubElement(intersect, 'second', {'ref': tubeName}) + pos = edge.Curve.Center + Vector(0, 0, self.height/2) + exportPosition(tubeName, intersect, pos) + rotName = tubeName+'_rot' + # zAngle = math.degrees(edge.Curve.AngleXU) + # Focus1 is on the positive x side, Focus2 on the negative side + dy = edge.Curve.Focus1[1] - edge.Curve.Focus2[1] + dx = edge.Curve.Focus1[0] - edge.Curve.Focus2[0] + zAngle = math.degrees(math.atan2(dy, dx)) + print(f'{self.name} zAngle = {zAngle}') + # if zAngle < 0: + # zAngle += 180 + ET.SubElement(define, 'rotation', {'name': rotName, 'unit': 'deg', + 'x': '0', 'y': '0', 'z': str(zAngle)}) + + ET.SubElement(intersect, 'rotationref', {'ref': rotName}) + + +class Extruded2Edges(ExtrudedClosedCurve): + def __init__(self, name, edgelist, height): + super().__init__(name, edgelist, height) + + def export(self): + global solids + + # form normals to the edges. For case of two edges, sidedness is irrelevant + v0 = self.edgeList[0].Vertexes[0].Point + v1 = self.edgeList[0].Vertexes[1].Point + e = v1 - v0 + if e.x == 0: + ny = 0 + nx = 1 + elif e.y == 0: + nx = 0 + ny = 1 + else: + nx = 1 + ny = -e.x/e.y + normal = Vector(nx, ny, 0).normalize() + + edgeCurves = [] # list of ExtrudedClosedCurve's + + for i, e in enumerate(self.edgeList): # just TWO edges + while switch(e.Curve.TypeId): + if case('Part::GeomLineSegment'): + break + + if case('Part::GeomLine'): + break + + if case('Part::GeomCircle'): + print('Arc of Circle') + arcXtruName = self.name + '_c'+str(i) + arcSection = ExtrudedArcSection(arcXtruName, [e], self.height) + arcSection.export() + + midpnt = arcSection.midPoint() + inside = pointInsideEdge(midpnt, v0, normal) + edgeCurves.append([arcXtruName, inside]) + break + + if case('Part::GeomEllipse'): + print('Arc of Ellipse') + arcXtruName = self.name+'_e'+str(i) + arcSection = ExtrudedEllipticalSection(arcXtruName, [e], self.height) + arcSection.export() + midpnt = arcSection.midPoint() + inside = pointInsideEdge(midpnt, v0, normal) + edgeCurves.append([arcXtruName, inside]) + break + + if case('Part::GeomBSplineCurve'): + print('BSpline not implemented yet') + break + + if len(edgeCurves) == 1: + # change our name to be that of the constructed curve + # not a violation of the contract of a unique name, since the curve name is based on ours + self.position = arcSection.position + self.rotation = arcSection.rotation + self.name = edgeCurves[0][0] + + else: + inside0 = edgeCurves[0][1] + inside1 = edgeCurves[1][1] + sameSide = (inside0 == inside1) + if sameSide is False: + booleanSolid = ET.SubElement(solids, 'union', {'name': self.name}) + else: + booleanSolid = ET.SubElement(solids, 'subtraction', {'name': self.name}) + + area0 = edgelistBBoxArea([self.edgeList[0]]) + area1 = edgelistBBoxArea([self.edgeList[1]]) + if area0 > area1: + firstSolid = edgeCurves[0][0] + secondSolid = edgeCurves[1][0] + else: + firstSolid = edgeCurves[1][0] + secondSolid = edgeCurves[0][0] + + ET.SubElement(booleanSolid, 'first', {'ref': firstSolid}) + ET.SubElement(booleanSolid, 'second', {'ref': secondSolid}) + + +class ExtrudedNEdges(ExtrudedClosedCurve): + def __init__(self, name, edgelist, height): + super().__init__(name, edgelist, height) + + def export(self): + global solids + from .exportGDML import exportPosition + + verts = [] + for e in self.edgeList: + if len(e.Vertexes) > 1: + verts.append(e.Vertexes[0].Point) + verts.append(verts[0]) + + face = Part.Face(Part.makePolygon(verts)) + + edgeCurves = [] # list of ExtrudedClosedCurve's + for i, e in enumerate(self.edgeList): + + while switch(e.Curve.TypeId): + if case('Part::GeomLineSegment'): + break + + if case('Part::GeomLine'): + break + + if case('Part::GeomCircle'): + print('Arc of Circle') + arcXtruName = self.name + '_c'+str(i) + arcSection = ExtrudedArcSection(arcXtruName, [e], self.height) + midpnt = arcSection.midPoint() + inside = face.isInside(midpnt, 0.001, True) + if inside is True: + arcSection.height = 1.02*self.height # for a cutting solid, increase its height + arcSection.export() + # this is not general. Needs to be changed + # to a test against sidedness of edge of section + edgeCurves.append([arcXtruName, inside]) + break + + if case('Part::GeomEllipse'): + print('Arc of Ellipse') + arcXtruName = self.name+'_e'+str(i) + arcSection = ExtrudedEllipticalSection(arcXtruName, [e], self.height) + midpnt = arcSection.midPoint() + inside = face.isInside(midpnt, 0.001, True) + if inside is True: + arcSection.height = 1.02*self.height # for a cutting solid, increase its height + arcSection.export() + edgeCurves.append([arcXtruName, inside]) + break + + if case('Part::GeomBSplineCurve'): + print('BSpline not implemented yet') + break + + xtruName = self.name + if len(edgeCurves) > 0: + xtruName += '_xtru' + exportXtru(xtruName, verts, self.height) + + currentSolid = xtruName + if len(edgeCurves) > 0: + for i, c in enumerate(edgeCurves): + if i == len(edgeCurves) - 1: + name = self.name # last boolean must have this classes name + else: + name = 'bool' + c[0] + if c[1] is False: + booleanSolid = ET.SubElement(solids, 'union', {'name': name}) + ET.SubElement(booleanSolid, 'first', {'ref': currentSolid}) + ET.SubElement(booleanSolid, 'second', {'ref': c[0]}) + else: + booleanSolid = ET.SubElement(solids, 'subtraction', {'name': name}) + pos = Vector(0,0, -0.01*self.height) # move subtracted solid down a bit + ET.SubElement(booleanSolid, 'first', {'ref': currentSolid}) + ET.SubElement(booleanSolid, 'second', {'ref': c[0]}) + exportPosition(c[0], booleanSolid, pos) + currentSolid = name + +# Node of a tree that represents the topology of the sketch being exported +# a left_child is a ClosedCurve that is inside of its parent +# a right_sibling is a closedCurve that is outside of its parent + + +class Node: + def __init__(self, closedCurve, parent, parity): + # the nomenclature is redundant, but a reminder that left is a child and right + # a sibling + self.parent = parent + if parent is None: + self.parity = 0 # if parity is 0, print as union with current solid + # if parity is 1, print as subtraction from other solid + else: + self.parity = parity + + self.left_child = None + self.right_sibling = None + self.closedCurve = closedCurve + + def insert(self, closedCurve): + if self.closedCurve: # not sure why this test is necessary + if self.closedCurve.isInside(closedCurve): + # given curve is inside this curve: + # if this node does not have a child, insert it as the left_child + # otherwise check if it is a child of the child + if self.left_child is None: + self.left_child = Node(closedCurve, self, 1-self.parity) + else: + self.left_child.insert(closedCurve) + else: # Since we have no intersecting curves (for well constructed sketch + # if the given curve is not inside this node, it must be outside + if self.right_sibling is None: + self.right_sibling = Node(closedCurve, self, self.parity) + else: + self.right_sibling.insert(closedCurve) + else: + self.closedCurve = closedCurve + + def preOrderTraversal(self, root): + res = [] + if root: + res.append([root, root.parity]) + res = res + self.preOrderTraversal(root.left_child) + res = res + self.preOrderTraversal(root.right_sibling) + + return res + +# arrange a list of edges in the x-y plane in Counter Clock Wise direction +# This can be easily generalized for points in ANY plane: if the normal +# defining the desired direction of the plane is given, then the z component +# below should be changed a dot prduct with the normal + + +def arrangeCCW(verts, normal=Vector(0, 0, 1)): + reverse = False + v0 = verts[0] + rays = [(v - v0) for v in verts[1:]] + area = 0 + for i, ray in enumerate(rays[:-1]): + area += (rays[i].cross(rays[i+1])).dot(normal) + if area < 0: + verts.reverse() + reverse = True + + return reverse + +# Utility to determine if vector from point v0 to point v1 (v1-v0) +# is on sime side of normal or opposite. Return true if v ploints along normal + + +def pointInsideEdge(v0, v1, normal): + v = v1 - v0 + if v.dot(normal) < 0: + return False + else: + return True + + +def edgelistBB(edgelist): + # get edge list bounding box + bb = FreeCAD.BoundBox(0, 0, 0, 0, 0, 0) + for e in edgelist: + bb.add(e.BoundBox) + return bb + + +def edgelistBBoxArea(edgelist): + bb = edgelistBB(edgelist) + return bb.XLength * bb.YLength + + +def sortEdgelistsByBoundingBoxArea(listoflists): + listoflists.sort(reverse=True, key=edgelistBBoxArea) + + +def exportEllipticalTube(name, dx, dy, height): + global solids + + ET.SubElement(solids, 'eltube', {'name': name, + 'dx': str(dx), + 'dy': str(dy), + 'dz': str(height/2), + 'lunit': 'mm'}) + + +def exportTube(name, radius, height): + global solids + + ET.SubElement(solids, 'tube', {'name': name, + 'rmax': str(radius), + 'z': str(height), + 'startphi': '0', + 'deltaphi': '360', + 'aunit': 'deg', 'lunit': 'mm'}) + + +def exportXtru(name, vlist, height, zoffset=0): + global solids + + xtru = ET.SubElement(solids, 'xtru', {'name': name, 'lunit': 'mm'}) + for v in vlist: + ET.SubElement(xtru, 'twoDimVertex', {'x': str(v.x), + 'y': str(v.y)}) + ET.SubElement(xtru, 'section', {'zOrder': '0', + 'zPosition': str(zoffset), + 'xOffset': '0', 'yOffset': '0', + 'scalingFactor': '1'}) + ET.SubElement(xtru, 'section', {'zOrder': '1', + 'zPosition': str(height+zoffset), + 'xOffset': '0', 'yOffset': '0', + 'scalingFactor': '1'}) + + +def getExtrudedCurve(name, edges, height): + # Return an ExtrudedClosedCurve object of the list of edges + + if len(edges) == 1: # single edge ==> a closed curve, or curve section + e = edges[0] + if len(e.Vertexes) == 1: # a closed curve + closed = True + else: + closed = False # a section of a curve + + while switch(e.Curve.TypeId): + if case('Part::GeomLineSegment'): + print(' Sketch not closed') + return ExtrudedClosedCurve(edges, name, height) + + if case('Part::GeomLine'): + print(' Sketch not closed') + return ExtrudedClosedCurve(name, edges, height) + + if case('Part::GeomCircle'): + if closed is True: + print('Circle') + return ExtrudedCircle(name, edges, height) + else: + print('Arc of Circle') + return ExtrudedArcSection(name, edges, height) + + if case('Part::GeomEllipse'): + if closed is True: + print('Ellipse') + return ExtrudedEllipse(name, edges, height) + else: + print('Arc of Ellipse') + return ExtrudedEllipticalSection(name, edges, height) + + if case('Part::GeomBSplineCurve'): + print(' B spline extrusion not implemented yet') + return ExtrudedClosedCurve(name, edges, height) + + elif len(edges) == 2: # exactly two edges + return Extruded2Edges(name, edges, height) + else: # three or more edges + return ExtrudedNEdges(name, edges, height) + + +def setGlobals(defineV, materialsV, solidsV): + global define, materials, solids + define = defineV + materials = materialsV + solids = solidsV + + +# duplicate of exportDefine in exportGDML +def exportDefine(name, v): + global define + # print('define : '+name) + # print(v) + # print(v[0]) + ET.SubElement(define, 'position', {'name': name, 'unit': 'mm', + 'x': str(v[0]), + 'y': str(v[1]), + 'z': str(v[2])}) + + +# scale up a solid that will be subtracted so it ounched thru parent +def scaleUp(scaledName, originalName, zFactor): + ss = ET.SubElement(solids, 'scaledSolid', {'name': scaledName}) + ET.SubElement(ss, 'solidref', {'ref': originalName}) + ET.SubElement(ss, 'scale', {'name': originalName+'_ss', + 'x': '1', 'y': '1', 'z': str(zFactor)}) + + +def rotatedPos(closedCurve, rot): + # Circles and ellipses (tubes and elliptical tubes) are referenced to origin + # in GDML and have to be translated to their position via a position reference + # when placed as a physical volume. This is done by adding the translation + # to the Part::Extrusion Placement. However, if the placement includes + # a rotation, Geant4 GDML would rotate the Origin-based curve THEN translate. + # This would not work. We have to translate first THEN rotate. This method + # just does the needed rotation of the poisition vector + # + pos = closedCurve.position + if isinstance(closedCurve, ExtrudedCircle) or \ + isinstance(closedCurve, ExtrudedEllipse): + pos = rot*closedCurve.position + + return pos + + +def processExtrudedSketch(extrudeObj, sketchObj, xmlVol): + from .exportGDML import insertXMLvolume, exportPosition, addVolRef, \ + quaternion2XYZ + + sortededges = Part.sortEdges(sketchObj.Shape.Edges) + # sort by largest area to smallest area + sortEdgelistsByBoundingBoxArea(sortededges) + # getCurve returns one of the sub classes of ClosedCurve that + # knows how to export the specifc closed edges + # Make names based on Extrude name + # curves = [getCurve(edges, extrudeObj.Label + str(i)) for i, edges in enumerate(sortededges)] + if extrudeObj.Symmetric is True: + height = extrudeObj.LengthFwd.Value + else: + height = extrudeObj.LengthFwd.Value + extrudeObj.LengthRev.Value + eName = extrudeObj.Label + # get a list of curves (instances of class ClosedCurve) for each set of closed edges + curves = [getExtrudedCurve(eName+str(i), edges, height) + for i, edges in enumerate(sortededges)] + # build a generalized binary tree of closed curves. + root = Node(curves[0], None, 0) + for c in curves[1:]: + root.insert(c) + + # Traverse the tree. The list returned is a list of [Node, parity], where parity = 0, says add to parent, 1 mean subtract + lst = root.preOrderTraversal(root) + rootnode = lst[0][0] + rootCurve = rootnode.closedCurve + rootCurve.export() # a curve is created with a unique name + firstName = rootCurve.name + booleanName = firstName + + rootPos = rootCurve.position + rootRot = rootCurve.rotation # for now consider only angle of rotation about z-axis + + for c in lst[1:]: + node = c[0] + parity = c[1] + curve = node.closedCurve + curve.export() + if parity == 0: + boolType = 'union' + secondName = curve.name + secondPos = curve.position + else: + boolType = 'subtraction' + secondName = curve.name+'_s' # scale solids along z, so it punches thru + scaleUp(secondName, curve.name, 1.10) + secondPos = curve.position - Vector(0, 0, 0.01*height) + + booleanName = curve.name + '_bool' + boolSolid = ET.SubElement(solids, boolType, {'name': booleanName}) + ET.SubElement(boolSolid, 'first', {'ref': firstName}) + ET.SubElement(boolSolid, 'second', {'ref': secondName}) + relativePosition = secondPos - rootPos + zAngle = curve.rotation[2] - rootRot[2] + posName = curve.name+'_pos' + rotName = curve.name+'_rot' + exportDefine(posName, relativePosition) # position of second relative to first + ET.SubElement(define, 'rotation', {'name': rotName, 'unit': 'deg', + 'x': '0', 'y': '0', + 'z': str(zAngle)}) + + ET.SubElement(boolSolid, 'positionref', {'ref': posName}) + ET.SubElement(boolSolid, 'rotationref', {'ref': rotName}) + firstName = booleanName + + # now create logical and physical volumes for the last boolean. + # Because the position of each closed curve might not be at the + # origin, whereas primitives (tubes, cones, etc, are created centered at + # the origin, we need to shift the position of the very first node by its + # position, in addition to the shift by the Extrusion placement + volName = booleanName+'Vol' # booleanName is name of last boolean + newvol = insertXMLvolume(volName) + + addVolRef(newvol, volName, extrudeObj, booleanName) + # ET.SubElement(newvol,'materialref',{'ref': 'G4_Si'}) + # ET.SubElement(newvol,'solidref',{'ref': booleanName}) + + pvol = ET.SubElement(xmlVol, 'physvol', {'name': 'PV'+volName}) + ET.SubElement(pvol, 'volumeref', {'ref': volName}) + extrudePosition = extrudeObj.Placement.Base + if extrudeObj.Symmetric is False: + if extrudeObj.Reversed is False: + zoffset = Vector(0, 0, extrudeObj.LengthRev.Value) + else: + zoffset = Vector(0, 0, extrudeObj.LengthFwd.Value) + else: + zoffset = Vector(0, 0, extrudeObj.LengthFwd.Value/2) + + angles = quaternion2XYZ(extrudeObj.Placement.Rotation) + # need to add rotations of elliptical tubes. Assume extrusion is on z-axis + # Probably wil not work in general + zAngle = angles[2] + rootRot[2] + print(rootPos) + print(rootCurve.name) + print(rootCurve.position) + rootPos = rotatedPos(rootCurve, extrudeObj.Placement.Rotation) + print(rootPos) + volPos = extrudePosition + rootPos - zoffset + + print(volPos) + exportPosition(volName, pvol, volPos) + + rotName = booleanName + '_rot' + ET.SubElement(define, 'rotation', {'name': rotName, 'unit': 'deg', + 'x': str(-angles[0]), + 'y': str(-angles[1]), + 'z': str(-zAngle)}) + ET.SubElement(pvol, 'rotationref', {'ref': rotName}) diff --git a/freecad/gdml/exportGDML.py b/freecad/gdml/exportGDML.py index 6116c27b4..ddc488960 100644 --- a/freecad/gdml/exportGDML.py +++ b/freecad/gdml/exportGDML.py @@ -1,30 +1,30 @@ # Mon Dec 6 08:49:56 AM PST 2021 -#**************************************************************************pp -#* * -#* Copyright (c) 2019 Keith Sloan * -#* (c) 2020 Dam Lambert * -#* * -#* 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 * -#* * -#* Acknowledgements : Ideas & code copied from * -#* https://github.com/ignamv/geanTipi * -#* * -#*************************************************************************** -__title__="FreeCAD - GDML exporter Version" +# ************************************************************************** +# * * +# * Copyright (c) 2019 Keith Sloan * +# * (c) 2020 Dam Lambert * +# * * +# * 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 * +# * * +# * Acknowledgements : Ideas & code copied from * +# * https://github.com/ignamv/geanTipi * +# * * +# *************************************************************************** +__title__ = "FreeCAD - GDML exporter Version" __author__ = "Keith Sloan " __url__ = ["https://github.com/KeithSloan/FreeCAD_Geant4"] @@ -32,70 +32,75 @@ from FreeCAD import Vector from .GDMLObjects import GDMLcommon, GDMLBox, GDMLTube -# modif add -#from .GDMLObjects import getMult, convertionlisteCharToLunit +# modif add +# from .GDMLObjects import getMult, convertionlisteCharToLunit import sys try: - import lxml.etree as ET - FreeCAD.Console.PrintMessage("running with lxml.etree\n") - XML_IO_VERSION='lxml' + import lxml.etree as ET + FreeCAD.Console.PrintMessage("running with lxml.etree\n") + XML_IO_VERSION = 'lxml' except ImportError: - try: - import xml.etree.ElementTree as ET - FreeCAD.Console.PrintMessage("running with xml.etree.ElementTree\n") - XML_IO_VERSION = 'xml' - except ImportError: - FreeCAD.Console.PrintMessage('pb xml lib not found\n') - sys.exit() + try: + import xml.etree.ElementTree as ET + FreeCAD.Console.PrintMessage("running with xml.etree.ElementTree\n") + XML_IO_VERSION = 'xml' + except ImportError: + FreeCAD.Console.PrintMessage('pb xml lib not found\n') + sys.exit() # xml handling -#import argparse -#from xml.etree.ElementTree import XML +# import argparse +# from xml.etree.ElementTree import XML ################################# -try: import FreeCADGui -except ValueError: gui = False -else: gui = True - global zOrder from .GDMLObjects import GDMLQuadrangular, GDMLTriangular, \ GDML2dVertex, GDMLSection, \ GDMLmaterial, GDMLfraction, \ GDMLcomposite, GDMLisotope, \ - GDMLelement, GDMLconstant, GDMLvariable, GDMLquantity + GDMLelement, GDMLconstant, GDMLvariable, \ + GDMLquantity from . import GDMLShared +from . import exportExtrusion -#*************************************************************************** +# *************************************************************************** # Tailor following to your requirements ( Should all be strings ) * # no doubt there will be a problem when they do implement Value if open.__module__ in ['__builtin__', 'io']: - pythonopen = open # to distinguish python built-in open function from the one declared here + pythonopen = open # to distinguish python built-in open function from the one declared here + +# ## modifs lambda -### modifs lambda def verifNameUnique(name): - # need to be done!! - return True + # need to be done!! + return True -### end modifs lambda +# ## end modifs lambda ################################# # Switch functions ################################ + + class switch(object): value = None + def __new__(class_, value): class_.value = value return True + def case(*args): return any((arg == switch.value for arg in args)) ######################################################### # Pretty format GDML # ######################################################### + + def indent(elem, level=0): i = "\n" + level*" " j = "\n" + (level-1)*" " @@ -113,29 +118,31 @@ def indent(elem, level=0): elem.tail = j return elem -def nameFromLabel(label) : - if ' ' not in label : - return label - else : - return(label.split(' ')[0]) +######################################### + +def nameFromLabel(label): + if ' ' not in label: + return label + else: + return(label.split(' ')[0]) -def initGDML() : + +def initGDML(): NS = 'http://www.w3.org/2001/XMLSchema-instance' location_attribute = '{%s}noNamespaceSchemaLocation' % NS - gdml = ET.Element('gdml',attrib={location_attribute: \ - 'http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd'}) - #print(gdml.tag) + gdml = ET.Element('gdml', attrib={location_attribute: + 'http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd'}) + # print(gdml.tag) - #'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance", - #'xsi:noNamespaceSchemaLocation': "http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd" -#}) return gdml ################################# # Setup GDML environment ################################# -def GDMLstructure() : - #print("Setup GDML structure") + + +def GDMLstructure(): + # print("Setup GDML structure") ################################# # globals ################################ @@ -145,7 +152,7 @@ def GDMLstructure() : global defineCnt, LVcount, PVcount, POScount, ROTcount global gxml - defineCnt = LVcount = PVcount = POScount = ROTcount = 1 + defineCnt = LVcount = PVcount = POScount = ROTcount = 1 gdml = initGDML() define = ET.SubElement(gdml, 'define') @@ -154,51 +161,113 @@ def GDMLstructure() : structure = ET.SubElement(gdml, 'structure') setup = ET.SubElement(gdml, 'setup', {'name': 'Default', 'version': '1.0'}) gxml = ET.Element('gxml') + + exportExtrusion.setGlobals(define, materials, solids) + return structure + def defineMaterials(): # Replaced by loading Default - #print("Define Materials") + # print("Define Materials") global materials -def exportDefine(name, v) : + +def exportDefine(name, v): global define - #print('define : '+name) - #print(v) - #print(v[0]) - ET.SubElement(define,'position',{'name' : name, 'unit': 'mm', \ - 'x': str(v[0]), 'y': str(v[1]), 'z': str(v[2]) }) + ET.SubElement(define, 'position', {'name': name, 'unit': 'mm', + 'x': str(v[0]), 'y': str(v[1]), 'z': str(v[2])}) + -def exportDefineVertex(name, v, index) : +def exportDefineVertex(name, v, index): global define - #print('define Vertex : '+name) - #print(v) - ET.SubElement(define,'position',{'name' : name + str(index), \ - 'unit': 'mm', 'x': str(v.X), 'y': str(v.Y), 'z': str(v.Z) }) + ET.SubElement(define, 'position', {'name': name + str(index), + 'unit': 'mm', 'x': str(v.X), 'y': str(v.Y), 'z': str(v.Z)}) + def defineWorldBox(bbox): global solids - for obj in FreeCAD.ActiveDocument.Objects : + for obj in FreeCAD.ActiveDocument.Objects: # print("{} + {} = ".format(bbox, obj.Shape.BoundBox)) - if hasattr(obj,"Shape"): - bbox.add(obj.Shape.BoundBox) - if hasattr(obj,"Mesh"): - bbox.add(obj.Mesh.BoundBox) - if hasattr(obj,"Points"): - bbox.add(obj.Points.BoundBox) + if hasattr(obj, "Shape"): + bbox.add(obj.Shape.BoundBox) + if hasattr(obj, "Mesh"): + bbox.add(obj.Mesh.BoundBox) + if hasattr(obj, "Points"): + bbox.add(obj.Points.BoundBox) # print(bbox) # Solids get added to solids section of gdml ( solids is a global ) name = 'WorldBox' ET.SubElement(solids, 'box', {'name': name, - 'x': str(1000), \ - 'y': str(1000), \ - 'z': str(1000), \ - #'x': str(2*max(abs(bbox.XMin), abs(bbox.XMax))), \ - #'y': str(2*max(abs(bbox.YMin), abs(bbox.YMax))), \ - #'z': str(2*max(abs(bbox.ZMin), abs(bbox.ZMax))), \ - 'lunit': 'mm'}) + 'x': str(1000), + 'y': str(1000), + 'z': str(1000), + # 'x': str(2*max(abs(bbox.XMin), abs(bbox.XMax))), \ + # 'y': str(2*max(abs(bbox.YMin), abs(bbox.YMax))), \ + # 'z': str(2*max(abs(bbox.ZMin), abs(bbox.ZMax))), \ + 'lunit': 'mm'}) return(name) + +def quaternion2XYZ(rot): + ''' + convert a quaternion rotation to a sequence of rotations around X, Y, Z + Here is my (Munther Hindi) derivation: + First, the rotation matrices for rotations around X, Y, Z axes. + + Rx = [ 1 0 0] + [ 0 cos(a) -sin(a)] + [ 0 sin(a) cos(a)] + + Ry= [ cos(b) 0 sin(b)] + [ 0 1 0] + [-sin(b) 0 cos(b)] + + Rz = [ cos(g) -sin(g) 0] + [ sin(g) cos(g) 0] + [ 0 0 1] + + R = Rz Ry Rx = [ + [cos(b)*cos(g), cos(g)*sin(a)*sin(b) - cos(a)*sin(g), cos(a)*cos(g)*sin(b) + sin(a)*sin(g)] + [cos(b)*sin(g), sin(a)*sin(b)*sin(g) + cos(a)*cos(g), cos(a)*sin(b)*sin(g) - cos(g)*sin(a)] + [-sin(b), cos(b)*sin(a), , cos(a)*cos(b)]] + + To get the angles b(eta), g(amma) for rotations around y, z axes, transform the unit vector (1,0,0) + [x,y,z] = Q*(1,0,0) = R*(1,0,0) ==> + x = cos(b)*cos(g) + y = cos(b)*sin(g) + z = -sin(b) + + ==> g = atan2(y, x) = atan2(sin(b)*sin(g), cos(g)*sin(b)) = atan2(sin(g), cos(g)) + then b = atan2(-z*cos(g), x) = atan2(sin(b)*cos(g), cos(b)*cos(g)] = atan2(sin(b), cos(b)) + + Once b, g are found, a(lpha) can be found by transforming (0, 0, 1), or (0,1,0) + Since now g, b are known, one can form the inverses of Ry, Rz: + Rz^-1 = Rz(-g) + Ry^-1 = Ry(-b) + + Now R*(0,0,1) = Rz*Ry*Rz(0,1,0) = (x, y, z) + multiply both sides by Ry^-1 Rz^-1: + Ry^-1 Rz^-1 Rz Ry Rx (0,1,0) = Rx (0,1,0) = Ry(-b) Rz(-g) (x, y, z) = (xp, yp, zp) + ==> + xp = 0 + yp = cos(a) + zp = sin(a) + + and a = atan2(zp, yp) + ''' + v = rot*Vector(1, 0, 0) + g = math.atan2(v.y, v.x) + b = math.atan2(-v.z*math.cos(g), v.x) + Ryinv = FreeCAD.Rotation(Vector(0, 1, 0), math.degrees(-b)) + Rzinv = FreeCAD.Rotation(Vector(0, 0, 1), math.degrees(-g)) + vp = Ryinv*Rzinv*rot*Vector(0, 1, 0) + a = math.atan2(vp.z, vp.y) + + print([math.degrees(a), math.degrees(b), math.degrees(g)]) + return [math.degrees(a), math.degrees(b), math.degrees(g)] + + def createLVandPV(obj, name, solidName): # # Logical & Physical Volumes get added to structure section of gdml @@ -206,32 +275,25 @@ def createLVandPV(obj, name, solidName): # Need to update so that use export of Rotation & position # rather than this as well i.e one Place # - #print('createLVandPV') - #ET.ElementTree(gdml).write("test9d", 'utf-8', True) - #print("Object Base") - #dir(obj.Base) - #print dir(obj) - #print dir(obj.Placement) global PVcount, POScount, ROTcount - #return pvName = 'PV'+name+str(PVcount) PVcount += 1 - pos = obj.Placement.Base - lvol = ET.SubElement(structure,'volume', {'name':pvName}) + pos = obj.Placement.Base + lvol = ET.SubElement(structure, 'volume', {'name': pvName}) ET.SubElement(lvol, 'materialref', {'ref': 'SSteel0x56070ee87d10'}) ET.SubElement(lvol, 'solidref', {'ref': solidName}) # Place child physical volume in World Volume - phys = ET.SubElement(lvol, 'physvol',{'name':'PV-'+name}) + phys = ET.SubElement(lvol, 'physvol', {'name': 'PV-'+name}) ET.SubElement(phys, 'volumeref', {'ref': pvName}) x = pos[0] y = pos[1] z = pos[2] - if x!=0 and y!=0 and z!=0 : - posName = 'Pos'+name+str(POScount) - POScount += 1 - ET.SubElement(phys, 'positionref', {'name': posName}) - ET.SubElement(define, 'position', {'name': posName, 'unit': 'mm', \ - 'x': str(x), 'y': str(y), 'z': str(z) }) + if x != 0 and y != 0 and z != 0: + posName = 'Pos'+name+str(POScount) + POScount += 1 + ET.SubElement(phys, 'positionref', {'name': posName}) + ET.SubElement(define, 'position', {'name': posName, 'unit': 'mm', + 'x': str(x), 'y': str(y), 'z': str(z)}) # Realthunders enhancement to toEuler ixyz is intrinsic rot = obj.Placement.Rotation if hasattr(rot, 'toEulerAngles'): @@ -243,196 +305,204 @@ def createLVandPV(obj, name, solidName): angles = rot.toEuler() GDMLShared.trace("Angles") GDMLShared.trace(angles) + angles = quaternion2XYZ(rot) a0 = angles[0] - #print(a0) + # print(a0) a1 = angles[1] - #print(a1) + # print(a1) a2 = angles[2] - #print(a2) - if a0!=0 and a1!=0 and a2!=0 : - rotName = 'Rot'+name+str(ROTcount) - ROTcount += 1 - ET.SubElement(phys, 'rotationref', {'name': rotName}) - ET.SubElement(define, 'rotation', {'name': rotName, 'unit': 'deg', \ - 'x': str(-a2), 'y': str(-a1), 'z': str(-a0)}) + # print(a2) + if a0 != 0 and a1 != 0 and a2 != 0: + rotName = 'Rot'+name+str(ROTcount) + ROTcount += 1 + ET.SubElement(phys, 'rotationref', {'name': rotName}) + ET.SubElement(define, 'rotation', {'name': rotName, 'unit': 'deg', + 'x': str(-a0), 'y': str(-a1), 'z': str(-a2)}) + def createAdjustedLVandPV(obj, name, solidName, delta): # Allow for difference in placement between FreeCAD and GDML adjObj = obj rot = FreeCAD.Rotation(obj.Placement.Rotation) - adjObj.Placement.move(rot.multVec(delta))#.negative() + adjObj.Placement.move(rot.multVec(delta)) # .negative() createLVandPV(adjObj, name, solidName) -def reportObject(obj) : - + +def reportObject(obj): + GDMLShared.trace("Report Object") GDMLShared.trace(obj) GDMLShared.trace("Name : "+obj.Name) - GDMLShared.trace("Type : "+obj.TypeId) - if hasattr(obj,'Placement') : - print("Placement") - print("Pos : "+str(obj.Placement.Base)) - print("axis : "+str(obj.Placement.Rotation.Axis)) - print("angle : "+str(obj.Placement.Rotation.Angle)) - - while switch(obj.TypeId) : - - ########################################### - # FreeCAD GDML Parts # - ########################################### - if case("Part::FeaturePython") : - GDMLShared.trace("Part::FeaturePython") - # - #if hasattr(obj.Proxy,'Type'): - # print (obj.Proxy.Type) - # print (obj.Name) - #else : - # print("Not a GDML Feature") - - #print dir(obj) - #print dir(obj.Proxy) - #print("cylinder : Height "+str(obj.Height)+ " Radius "+str(obj.Radius)) - break - ########################################### - # FreeCAD Parts # - ########################################### - if case("Part::Sphere") : - print("Sphere Radius : "+str(obj.Radius)) - break - - if case("Part::Box") : - print("cube : ("+ str(obj.Length)+","+str(obj.Width)+","+str(obj.Height)+")") - break - - if case("Part::Cylinder") : - print("cylinder : Height "+str(obj.Height)+ " Radius "+str(obj.Radius)) - break - - if case("Part::Cone") : - print("cone : Height "+str(obj.Height)+ " Radius1 "+str(obj.Radius1)+" Radius2 "+str(obj.Radius2)) - break - - if case("Part::Torus") : - print("Torus") - print(obj.Radius1) - print(obj.Radius2) - break - - if case("Part::Prism") : - print("Prism") - break - - if case("Part::RegularPolygon") : - print("RegularPolygon") - break - - if case("Part::Extrusion") : - print("Extrusion") - break - - if case("Circle") : - print("Circle") - break - - if case("Extrusion") : - print("Wire extrusion") - break - - if case("Mesh::Feature") : - print("Mesh") - #print dir(obj.Mesh) - break - - print("Other") - print(obj.TypeId) - break - -def processPlanar(obj, shape, name ) : - print ('Polyhedron ????') + GDMLShared.trace("Type : "+obj.TypeId) + if hasattr(obj, 'Placement'): + print("Placement") + print("Pos : "+str(obj.Placement.Base)) + print("axis : "+str(obj.Placement.Rotation.Axis)) + print("angle : "+str(obj.Placement.Rotation.Angle)) + + while switch(obj.TypeId): + + ########################################### + # FreeCAD GDML Parts # + ########################################### + if case("Part::FeaturePython"): + GDMLShared.trace("Part::FeaturePython") + # + # if hasattr(obj.Proxy,'Type'): + # print (obj.Proxy.Type) + # print (obj.Name) + # else : + # print("Not a GDML Feature") + + # print dir(obj) + # print dir(obj.Proxy) + # print("cylinder : Height "+str(obj.Height)+ " Radius "+str(obj.Radius)) + break + ########################################### + # FreeCAD Parts # + ########################################### + if case("Part::Sphere"): + print("Sphere Radius : "+str(obj.Radius)) + break + + if case("Part::Box"): + print("cube : (" + str(obj.Length)+"," + str(obj.Width)+"," + + str(obj.Height) + ")") + break + + if case("Part::Cylinder"): + print("cylinder : Height " + str(obj.Height) + + " Radius "+str(obj.Radius)) + break + + if case("Part::Cone"): + print("cone : Height "+str(obj.Height) + + " Radius1 "+str(obj.Radius1)+" Radius2 "+str(obj.Radius2)) + break + + if case("Part::Torus"): + print("Torus") + print(obj.Radius1) + print(obj.Radius2) + break + + if case("Part::Prism"): + print("Prism") + break + + if case("Part::RegularPolygon"): + print("RegularPolygon") + break + + if case("Part::Extrusion"): + print("Extrusion") + break + + if case("Circle"): + print("Circle") + break + + if case("Extrusion"): + print("Wire extrusion") + break + + if case("Mesh::Feature"): + print("Mesh") + # print dir(obj.Mesh) + break + + print("Other") + print(obj.TypeId) + break + + +def processPlanar(obj, shape, name): + print('Polyhedron ????') global defineCnt # - #print("Add tessellated Solid") - tess = ET.SubElement(solids,'tessellated',{'name': name}) - #print("Add Vertex positions") - for f in shape.Faces : - baseVrt = defineCnt - for vrt in f.Vertexes : - vnum = 'v'+str(defineCnt) - ET.SubElement(define, 'position', {'name': vnum, \ - 'x': str(vrt.Point.x), \ - 'y': str(vrt.Point.y), \ - 'z': str(vrt.Point.z), \ - 'unit': 'mm'}) - defineCnt += 1 - #print("Add vertex to tessellated Solid") - vrt1 = 'v'+str(baseVrt) - vrt2 = 'v'+str(baseVrt+1) - vrt3 = 'v'+str(baseVrt+2) - vrt4 = 'v'+str(baseVrt+3) - NumVrt = len(f.Vertexes) - if NumVrt == 3 : - ET.SubElement(tess,'triangular',{ \ - 'vertex1': vrt1, \ - 'vertex2': vrt2, \ - 'vertex3': vrt3, \ - 'type': 'ABSOLUTE'}) - elif NumVrt == 4 : - ET.SubElement(tess,'quadrangular',{ \ - 'vertex1': vrt1, \ - 'vertex2': vrt2, \ - 'vertex3': vrt3, \ - 'vertex4': vrt4, \ - 'type': 'ABSOLUTE'}) - -def checkShapeAllPlanar(Shape) : - for f in Shape.Faces : - if f.Surface.isPlanar() == False : - return False - break + # print("Add tessellated Solid") + tess = ET.SubElement(solids, 'tessellated', {'name': name}) + # print("Add Vertex positions") + for f in shape.Faces: + baseVrt = defineCnt + for vrt in f.Vertexes: + vnum = 'v'+str(defineCnt) + ET.SubElement(define, 'position', {'name': vnum, + 'x': str(vrt.Point.x), + 'y': str(vrt.Point.y), + 'z': str(vrt.Point.z), + 'unit': 'mm'}) + defineCnt += 1 + # print("Add vertex to tessellated Solid") + vrt1 = 'v'+str(baseVrt) + vrt2 = 'v'+str(baseVrt+1) + vrt3 = 'v'+str(baseVrt+2) + vrt4 = 'v'+str(baseVrt+3) + NumVrt = len(f.Vertexes) + if NumVrt == 3: + ET.SubElement(tess, 'triangular', { + 'vertex1': vrt1, + 'vertex2': vrt2, + 'vertex3': vrt3, + 'type': 'ABSOLUTE'}) + elif NumVrt == 4: + ET.SubElement(tess, 'quadrangular', { + 'vertex1': vrt1, + 'vertex2': vrt2, + 'vertex3': vrt3, + 'vertex4': vrt4, + 'type': 'ABSOLUTE'}) + + +def checkShapeAllPlanar(Shape): + for f in Shape.Faces: + if f.Surface.isPlanar() is False: + return False return True # Add XML for TessellateSolid -def mesh2Tessellate(mesh, name) : - global defineCnt - - baseVrt = defineCnt - #print ("mesh") - #print (mesh) - #print ("Facets") - #print (mesh.Facets) - #print ("mesh topology") - #print (dir(mesh.Topology)) - #print (mesh.Topology) -# -# mesh.Topology[0] = points -# mesh.Topology[1] = faces -# -# First setup vertex in define section vetexs (points) - #print("Add Vertex positions") - for fc_points in mesh.Topology[0] : - #print(fc_points) - v = 'v'+str(defineCnt) - ET.SubElement(define, 'position', {'name': v, \ - 'x': str(fc_points[0]), \ - 'y': str(fc_points[1]), \ - 'z': str(fc_points[2]), \ - 'unit': 'mm'}) - defineCnt += 1 -# -# Add faces -# - #print("Add Triangular vertex") - tess = ET.SubElement(solids,'tessellated',{'name': name}) - for fc_facet in mesh.Topology[1] : - #print(fc_facet) - vrt1 = 'v'+str(baseVrt+fc_facet[0]) - vrt2 = 'v'+str(baseVrt+fc_facet[1]) - vrt3 = 'v'+str(baseVrt+fc_facet[2]) - ET.SubElement(tess,'triangular',{ \ - 'vertex1': vrt1, 'vertex2': vrt2 ,'vertex3': vrt3, 'type': 'ABSOLUTE'}) - - -def processMesh(obj, Mesh, Name) : +def mesh2Tessellate(mesh, name): + global defineCnt + + baseVrt = defineCnt + # print ("mesh") + # print (mesh) + # print ("Facets") + # print (mesh.Facets) + # print ("mesh topology") + # print (dir(mesh.Topology)) + # print (mesh.Topology) + # + # mesh.Topology[0] = points + # mesh.Topology[1] = faces + # + # First setup vertex in define section vetexs (points) + # print("Add Vertex positions") + for fc_points in mesh.Topology[0]: + # print(fc_points) + v = 'v'+str(defineCnt) + ET.SubElement(define, 'position', {'name': v, + 'x': str(fc_points[0]), + 'y': str(fc_points[1]), + 'z': str(fc_points[2]), + 'unit': 'mm'}) + defineCnt += 1 + # + # Add faces + # + # print("Add Triangular vertex") + tess = ET.SubElement(solids, 'tessellated', {'name': name}) + for fc_facet in mesh.Topology[1]: + # print(fc_facet) + vrt1 = 'v'+str(baseVrt+fc_facet[0]) + vrt2 = 'v'+str(baseVrt+fc_facet[1]) + vrt3 = 'v'+str(baseVrt+fc_facet[2]) + ET.SubElement(tess, 'triangular', { + 'vertex1': vrt1, 'vertex2': vrt2, + 'vertex3': vrt3, 'type': 'ABSOLUTE'}) + + +def processMesh(obj, Mesh, Name): # obj needed for Volune names # object maynot have Mesh as part of Obj # Name - allows control over name @@ -441,192 +511,208 @@ def processMesh(obj, Mesh, Name) : mesh2Tessellate(Mesh, Name) return(Name) -def shape2Mesh(shape) : - import MeshPart - return (MeshPart.meshFromShape(Shape=shape, Deflection = 0.0)) -# Deflection= params.GetFloat('meshdeflection',0.0)) -def processObjectShape(obj) : +def shape2Mesh(shape): + import MeshPart + return (MeshPart.meshFromShape(Shape=shape, Deflection=0.0)) +# Deflection= params.GetFloat('meshdeflection',0.0)) + + +def processObjectShape(obj): # Check if Planar # If plannar create Tessellated Solid with 3 & 4 vertex as appropriate # If not planar create a mesh and the a Tessellated Solid with 3 vertex - #print("Process Object Shape") - #print(obj) - #print(obj.PropertiesList) - if not hasattr(obj,'Shape') : - return + # print("Process Object Shape") + # print(obj) + # print(obj.PropertiesList) + if not hasattr(obj, 'Shape'): + return shape = obj.Shape - #print (shape) - #print(shape.ShapeType) - while switch(shape.ShapeType) : - if case("Mesh::Feature") : - print("Mesh - Should not occur should have been handled") - #print("Mesh") - #tessellate = mesh2Tessellate(mesh) - #return(tessellate) - #break - - print("ShapeType Not handled") - print(shape.ShapeType) - break + # print (shape) + # print(shape.ShapeType) + while switch(shape.ShapeType): + if case("Mesh::Feature"): + print("Mesh - Should not occur should have been handled") + # print("Mesh") + # tessellate = mesh2Tessellate(mesh) + # return(tessellate) + # break + + print("ShapeType Not handled") + print(shape.ShapeType) + break # Dropped through to here # Need to check has Shape - #print('Check if All planar') + # print('Check if All planar') planar = checkShapeAllPlanar(shape) - #print(planar) + # print(planar) - if planar : - return(processPlanar(obj,shape,obj.Name)) + if planar: + return(processPlanar(obj, shape, obj.Name)) + + else: + # Create Mesh from shape & then Process Mesh + # to create Tessellated Solid in Geant4 + return(processMesh(obj, shape2Mesh(shape), obj.Name)) - else : - # Create Mesh from shape & then Process Mesh - #to create Tessellated Solid in Geant4 - return(processMesh(obj,shape2Mesh(shape),obj.Name)) -def processBoxObject(obj, addVolsFlag) : +def processBoxObject(obj, addVolsFlag): # Needs unique Name # This for non GDML Box - boxName = obj.Name - - ET.SubElement(solids, 'box',{'name': boxName, \ - 'x': str(obj.Length.Value), \ - 'y': str(obj.Width.Value), \ - 'z': str(obj.Height.Value), \ - 'lunit' : 'mm'}) - if addVolsFlag : - # Adjustment for position in GDML - delta = FreeCAD.Vector(obj.Length.Value / 2, \ - obj.Width.Value / 2, \ - obj.Height.Value / 2) - - createAdjustedLVandPV(obj, obj.Name, boxName, delta) + + boxName = obj.Name + + ET.SubElement(solids, 'box', {'name': boxName, + 'x': str(obj.Length.Value), + 'y': str(obj.Width.Value), + 'z': str(obj.Height.Value), + 'lunit': 'mm'}) + if addVolsFlag: + # Adjustment for position in GDML + delta = FreeCAD.Vector(obj.Length.Value / 2, + obj.Width.Value / 2, + obj.Height.Value / 2) + + createAdjustedLVandPV(obj, obj.Name, boxName, delta) return(boxName) -def processCylinderObject(obj, addVolsFlag) : + +def processCylinderObject(obj, addVolsFlag): # Needs unique Name # This is for non GDML cylinder/tube cylName = obj.Name - ET.SubElement(solids, 'tube',{'name': cylName, \ - 'rmax': str(obj.Radius.Value), \ - 'deltaphi': str(float(obj.Angle)), \ - 'aunit': obj.aunit, - 'z': str(obj.Height.Value), \ - 'lunit' : 'mm'}) - if addVolsFlag : - # Adjustment for position in GDML - delta = FreeCAD.Vector(0, 0, obj.Height.Value / 2) - createAdjustedLVandPV(obj, obj.Name, cylName, delta) + ET.SubElement(solids, 'tube', {'name': cylName, + 'rmax': str(obj.Radius.Value), + 'deltaphi': str(float(obj.Angle)), + 'aunit': obj.aunit, + 'z': str(obj.Height.Value), + 'lunit': 'mm'}) + if addVolsFlag: + # Adjustment for position in GDML + delta = FreeCAD.Vector(0, 0, obj.Height.Value / 2) + createAdjustedLVandPV(obj, obj.Name, cylName, delta) return(cylName) -def processConeObject(obj, addVolsFlag) : + +def processConeObject(obj, addVolsFlag): # Needs unique Name coneName = obj.Name - ET.SubElement(solids, 'cone',{'name': coneName, \ - 'rmax1': str(obj.Radius1.Value), \ - 'rmax2': str(obj.Radius2.Value), \ - 'deltaphi': str(float(obj.Angle)), \ - 'aunit': obj.aunit, - 'z': str(obj.Height.Value), \ - 'lunit' : 'mm'}) - if addVolsFlag : - # Adjustment for position in GDML - delta = FreeCAD.Vector(0, 0, obj.Height.Value / 2) - createAdjustedLVandPV(obj, obj.Name, coneName, delta) + ET.SubElement(solids, 'cone', { + 'name': coneName, + 'rmax1': str(obj.Radius1.Value), + 'rmax2': str(obj.Radius2.Value), + 'deltaphi': str(float(obj.Angle)), + 'aunit': obj.aunit, + 'z': str(obj.Height.Value), + 'lunit': 'mm'}) + if addVolsFlag: + # Adjustment for position in GDML + delta = FreeCAD.Vector(0, 0, obj.Height.Value / 2) + createAdjustedLVandPV(obj, obj.Name, coneName, delta) return(coneName) -def processSection(obj, addVolsflag) : - #print("Process Section") - ET.SubElement(solids, 'section',{'vertex1': obj.v1, \ - 'vertex2': obj.v2, 'vertex3': obj.v3, 'vertex4': obj.v4, \ - 'type': obj.vtype}) +def processSection(obj, addVolsflag): + # print("Process Section") + ET.SubElement(solids, 'section', { + 'vertex1': obj.v1, + 'vertex2': obj.v2, + 'vertex3': obj.v3, 'vertex4': obj.v4, + 'type': obj.vtype}) -def processSphereObject(obj, addVolsFlag) : + +def processSphereObject(obj, addVolsFlag): # Needs unique Name - #modif lambda (if we change the name here, each time we import and export the file, the name will be change - #sphereName = 'Sphere' + obj.Name + # modif lambda (if we change the name here, each time we import and export the file, the name will be change + # sphereName = 'Sphere' + obj.Name sphereName = obj.Name - ET.SubElement(solids, 'sphere',{'name': sphereName, \ - 'rmax': str(obj.Radius.Value), \ - 'starttheta': str(90.-float(obj.Angle2)), \ - 'deltatheta': str(float(obj.Angle2-obj.Angle1)), \ - 'deltaphi': str(float(obj.Angle3)), \ - 'aunit': obj.aunit, - 'lunit' : 'mm'}) - if addVolsFlag : - createLVandPV(obj,obj.Name,sphereName) + ET.SubElement(solids, 'sphere', { + 'name': sphereName, + 'rmax': str(obj.Radius.Value), + 'starttheta': str(90.-float(obj.Angle2)), + 'deltatheta': str(float(obj.Angle2-obj.Angle1)), + 'deltaphi': str(float(obj.Angle3)), + 'aunit': obj.aunit, + 'lunit': 'mm'}) + if addVolsFlag: + createLVandPV(obj, obj.Name, sphereName) return(sphereName) -def addPhysVol(xmlVol, volName) : - GDMLShared.trace("Add PhysVol to Vol : "+volName) - #print(ET.tostring(xmlVol)) - pvol = ET.SubElement(xmlVol,'physvol',{'name':'PV-'+volName}) - ET.SubElement(pvol,'volumeref',{'ref':volName}) + +def addPhysVol(xmlVol, volName): + GDMLShared.trace("Add PhysVol to Vol : " + volName) + # print(ET.tostring(xmlVol)) + pvol = ET.SubElement(xmlVol, 'physvol', {'name': 'PV-'+volName}) + ET.SubElement(pvol, 'volumeref', {'ref': volName}) return pvol -def cleanVolName(obj, volName) : + +def cleanVolName(obj, volName): # Get proper Volume Name - #print('clean name : '+volName) - if hasattr(obj,'Copynumber') : - #print('Has copynumber') - i = len(volName) - if '_' in volName and i > 2 : - volName = volName[:-2] - #print('returning name : '+volName) + # print('clean name : '+volName) + if hasattr(obj, 'Copynumber'): + # print('Has copynumber') + i = len(volName) + if '_' in volName and i > 2: + volName = volName[:-2] + # print('returning name : '+volName) return volName -def addPhysVolPlacement(obj, xmlVol, volName) : + +def addPhysVolPlacement(obj, xmlVol, volName): # ??? Is volName not obj.Label after correction # Get proper Volume Name refName = cleanVolName(obj, volName) - #GDMLShared.setTrace(True) - GDMLShared.trace("Add PhysVol to Vol : "+refName) - #print(ET.tostring(xmlVol)) - if xmlVol is not None : - if not hasattr(obj,'CopyNumber') : - pvol = ET.SubElement(xmlVol,'physvol',{'name':'PV-'+volName}) - else : - cpyNum = str(obj.CopyNumber) - GDMLShared.trace('CopyNumber : '+cpyNum) - pvol = ET.SubElement(xmlVol,'physvol',{'copynumber':cpyNum}) - ET.SubElement(pvol,'volumeref',{'ref':refName}) - processPosition(obj,pvol) - processRotation(obj,pvol) - if hasattr(obj,'GDMLscale') : - scaleName = refName+'scl' - ET.SubElement(pvol,'scale',{'name':scaleName,\ - 'x':str(obj.GDMLscale[0]), \ - 'y':str(obj.GDMLscale[1]), \ - 'z':str(obj.GDMLscale[2])}) - - return pvol - -def exportPosition(name, xml, pos) : + # GDMLShared.setTrace(True) + GDMLShared.trace("Add PhysVol to Vol : "+refName) + # print(ET.tostring(xmlVol)) + if xmlVol is not None: + if not hasattr(obj, 'CopyNumber'): + pvol = ET.SubElement(xmlVol, 'physvol', {'name': 'PV-' + volName}) + else: + cpyNum = str(obj.CopyNumber) + GDMLShared.trace('CopyNumber : '+cpyNum) + pvol = ET.SubElement(xmlVol, 'physvol', {'copynumber': cpyNum}) + ET.SubElement(pvol, 'volumeref', {'ref': refName}) + processPosition(obj, pvol) + processRotation(obj, pvol) + if hasattr(obj, 'GDMLscale'): + scaleName = refName+'scl' + ET.SubElement(pvol, 'scale', {'name': scaleName, + 'x': str(obj.GDMLscale[0]), + 'y': str(obj.GDMLscale[1]), + 'z': str(obj.GDMLscale[2])}) + + return pvol + + +def exportPosition(name, xml, pos): global POScount GDMLShared.trace('export Position') GDMLShared.trace(pos) x = pos[0] y = pos[1] z = pos[2] - posName = 'P-'+name+str(POScount) + posName = 'P-' + name + str(POScount) POScount += 1 - posxml = ET.SubElement(define,'position',{'name' : posName, \ - 'unit': 'mm'}) - if x != 0 : - posxml.attrib['x'] = str(x) - if y != 0 : - posxml.attrib['y'] = str(y) - if z != 0 : - posxml.attrib['z'] = str(z) - ET.SubElement(xml,'positionref',{'ref' : posName}) - -def exportRotation(name, xml, Rotation) : + posxml = ET.SubElement(define, 'position', {'name': posName, + 'unit': 'mm'}) + if x != 0: + posxml.attrib['x'] = str(x) + if y != 0: + posxml.attrib['y'] = str(y) + if z != 0: + posxml.attrib['z'] = str(z) + ET.SubElement(xml, 'positionref', {'ref': posName}) + + +def exportRotation(name, xml, Rotation): print('Export Rotation') global ROTcount - if Rotation.Angle != 0 : + if Rotation.Angle != 0: # Realthunders enhancement to toEuler ixyz is intrinsic if hasattr(Rotation, 'toEulerAngles'): angles = Rotation.toEulerAngles('ixyz') @@ -643,943 +729,1060 @@ def exportRotation(name, xml, Rotation) : print(a1) a2 = angles[2] print(a2) - if a0!=0 or a1!=0 or a2!=0 : + if a0 != 0 or a1 != 0 or a2 != 0: rotName = 'R-'+name+str(ROTcount) ROTcount += 1 - rotxml = ET.SubElement(define, 'rotation', {'name': rotName, \ - 'unit': 'deg'}) - if abs(a2) != 0 : - rotxml.attrib['x']=str(-a2) - if abs(a1) != 0 : - rotxml.attrib['y']=str(-a1) - if abs(a0) != 0 : - rotxml.attrib['z']=str(-a0) + rotxml = ET.SubElement(define, 'rotation', {'name': rotName, + 'unit': 'deg'}) + if abs(a2) != 0: + rotxml.attrib['x'] = str(-a2) + if abs(a1) != 0: + rotxml.attrib['y'] = str(-a1) + if abs(a0) != 0: + rotxml.attrib['z'] = str(-a0) ET.SubElement(xml, 'rotationref', {'ref': rotName}) -def processPosition(obj, solid) : - if obj.Placement.Base == FreeCAD.Vector(0,0,0) : + +def processPosition(obj, solid): + if obj.Placement.Base == FreeCAD.Vector(0, 0, 0): return GDMLShared.trace("Define position & references to Solid") exportPosition(obj.Name, solid, obj.Placement.Base) -def processRotation(obj, solid) : - if obj.Placement.Rotation.Angle == 0 : - return + +def processRotation(obj, solid): + if obj.Placement.Rotation.Angle == 0: + return GDMLShared.trace('Deal with Rotation') - exportRotation(obj.Name,solid,obj.Placement.Rotation) - -def testDefaultPlacement(obj) : - #print(dir(obj.Placement.Rotation)) - #print('Test Default Placement : '+obj.Name) - #print(obj.Placement.Base) - #print(obj.Placement.Rotation.Angle) - if obj.Placement.Base == FreeCAD.Vector(0,0,0) and \ - obj.Placement.Rotation.Angle == 0 : - return True - else : - return False + exportRotation(obj.Name, solid, obj.Placement.Rotation) + + +def testDefaultPlacement(obj): + # print(dir(obj.Placement.Rotation)) + # print('Test Default Placement : '+obj.Name) + # print(obj.Placement.Base) + # print(obj.Placement.Rotation.Angle) + if obj.Placement.Base == FreeCAD.Vector(0, 0, 0) and \ + obj.Placement.Rotation.Angle == 0: + return True + else: + return False + def testAddPhysVol(obj, xmlParent, volName): - if testDefaultPlacement(obj) == False : - if xmlParent is not None : - pvol = addPhysVol(xmlParent,volName) - processPosition(obj,pvol) - processRotation(obj,pvol) - else : - print('Root/World Volume') - -def addVolRef(volxml, volName, obj) : - # obj is GDML object + if testDefaultPlacement(obj) is False: + if xmlParent is not None: + pvol = addPhysVol(xmlParent, volName) + processPosition(obj, pvol) + processRotation(obj, pvol) + else: + print('Root/World Volume') + + +def addVolRef(volxml, volName, obj, solidName=None): # Pass material as Boolean material = getMaterial(obj) - ET.SubElement(volxml,'materialref',{'ref': material}) - ET.SubElement(volxml,'solidref',{'ref': nameOfGDMLobject(obj)}) - ET.SubElement(gxml,'volume',{'name': volName, 'material':material}) - if hasattr(obj.ViewObject,'ShapeColor') and volName != WorldVOL : - colour = obj.ViewObject.ShapeColor - colStr = '#'+''.join('{:02x}'.format(round(v*255)) for v in colour) - ET.SubElement(volxml,'auxiliary',{'auxtype': 'Color', 'auxvalue':colStr}) - #print(ET.tostring(volxml)) - -def nameOfGDMLobject(obj) : + if solidName is None: + solidName = nameOfGDMLobject(obj) + ET.SubElement(volxml, 'materialref', {'ref': material}) + ET.SubElement(volxml, 'solidref', {'ref': solidName}) + ET.SubElement(gxml, 'volume', {'name': volName, 'material': material}) + if hasattr(obj.ViewObject, 'ShapeColor') and volName != WorldVOL: + colour = obj.ViewObject.ShapeColor + colStr = '#'+''.join('{:02x}'.format(round(v*255)) for v in colour) + ET.SubElement(volxml, 'auxiliary', {'auxtype': 'Color', + 'auxvalue': colStr}) + # print(ET.tostring(volxml)) + + +def nameOfGDMLobject(obj): name = obj.Label - if len(name) > 4 : - if name[0:4] == 'GDML' : - if '_' in name : - return(name.split('_',1)[1]) + if len(name) > 4: + if name[0:4] == 'GDML': + if '_' in name: + return(name.split('_', 1)[1]) return name -def processGDMLArb8Object(obj) : + +def processGDMLArb8Object(obj): # Needs unique Name - # Remove leading GDMLArb8 from name on export + # Remove leading GDMLArb8 from name on export arb8Name = nameOfGDMLobject(obj) - solid = ET.Element('arb8',{'name': arb8Name, \ - 'v1x': str(obj.v1x), \ - 'v1y': str(obj.v1y), \ - 'v2x': str(obj.v2x), \ - 'v2y': str(obj.v2y), \ - 'v3x': str(obj.v3x), \ - 'v3y': str(obj.v3y), \ - 'v4x': str(obj.v4x), \ - 'v4y': str(obj.v4y), \ - 'v5x': str(obj.v5x), \ - 'v5y': str(obj.v5y), \ - 'v6x': str(obj.v6x), \ - 'v6y': str(obj.v6y), \ - 'v7x': str(obj.v7x), \ - 'v7y': str(obj.v7y), \ - 'v8x': str(obj.v8x), \ - 'v8y': str(obj.v8y), \ - 'dz': str(obj.dz), \ - 'lunit' : obj.lunit}) + solid = ET.SubElement(solids, 'arb8', {'name': arb8Name, + 'v1x': str(obj.v1x), + 'v1y': str(obj.v1y), + 'v2x': str(obj.v2x), + 'v2y': str(obj.v2y), + 'v3x': str(obj.v3x), + 'v3y': str(obj.v3y), + 'v4x': str(obj.v4x), + 'v4y': str(obj.v4y), + 'v5x': str(obj.v5x), + 'v5y': str(obj.v5y), + 'v6x': str(obj.v6x), + 'v6y': str(obj.v6y), + 'v7x': str(obj.v7x), + 'v7y': str(obj.v7y), + 'v8x': str(obj.v8x), + 'v8y': str(obj.v8y), + 'dz': str(obj.dz), + 'lunit': obj.lunit}) return solid, arb8Name -def processGDMLBoxObject(obj) : + +def processGDMLBoxObject(obj): # Needs unique Name - # Remove leading GDMLBox_ from name on export - boxName = nameOfGDMLobject(obj) - - solid = ET.Element('box',{'name': boxName, \ - 'x': str(obj.x), \ - 'y': str(obj.y), \ - 'z': str(obj.z), \ - 'lunit' : obj.lunit}) + # Remove leading GDMLBox_ from name on export + boxName = nameOfGDMLobject(obj) + + solid = ET.SubElement(solids, 'box', {'name': boxName, + 'x': str(obj.x), + 'y': str(obj.y), + 'z': str(obj.z), + 'lunit': obj.lunit}) return solid, boxName -def processGDMLConeObject(obj) : + +def processGDMLConeObject(obj): # Needs unique Name - # Remove leading GDMLTube_ from name on export + # Remove leading GDMLTube_ from name on export coneName = nameOfGDMLobject(obj) - solid = ET.Element('cone',{'name': coneName, \ - 'rmin1': str(obj.rmin1), \ - 'rmin2': str(obj.rmin2), \ - 'rmax1': str(obj.rmax1), \ - 'rmax2': str(obj.rmax2), \ - 'startphi': str(obj.startphi), \ - 'deltaphi': str(obj.deltaphi), \ - 'aunit': obj.aunit, \ - 'z': str(obj.z), \ - 'lunit' : obj.lunit}) + solid = ET.SubElement(solids, 'cone', {'name': coneName, + 'rmin1': str(obj.rmin1), + 'rmin2': str(obj.rmin2), + 'rmax1': str(obj.rmax1), + 'rmax2': str(obj.rmax2), + 'startphi': str(obj.startphi), + 'deltaphi': str(obj.deltaphi), + 'aunit': obj.aunit, + 'z': str(obj.z), + 'lunit': obj.lunit}) # modif 'mm' -> obj.lunit return solid, coneName -def processGDMLCutTubeObject(obj) : + +def processGDMLCutTubeObject(obj): # Needs unique Name # Remove leading GDML text from name cTubeName = nameOfGDMLobject(obj) - solid = ET.Element('cutTube',{'name': cTubeName, \ - 'rmin': str(obj.rmin), \ - 'rmax': str(obj.rmax), \ - 'startphi': str(obj.startphi), \ - 'deltaphi': str(obj.deltaphi), \ - 'aunit': obj.aunit, \ - 'z': str(obj.z), \ - 'highX':str(obj.highX), \ - 'highY':str(obj.highY), \ - 'highZ':str(obj.highZ), \ - 'lowX':str(obj.lowX), \ - 'lowY':str(obj.lowY), \ - 'lowZ':str(obj.lowZ), \ - 'lunit' : obj.lunit}) + solid = ET.SubElement(solids, 'cutTube', {'name': cTubeName, + 'rmin': str(obj.rmin), + 'rmax': str(obj.rmax), + 'startphi': str(obj.startphi), + 'deltaphi': str(obj.deltaphi), + 'aunit': obj.aunit, + 'z': str(obj.z), + 'highX': str(obj.highX), + 'highY': str(obj.highY), + 'highZ': str(obj.highZ), + 'lowX': str(obj.lowX), + 'lowY': str(obj.lowY), + 'lowZ': str(obj.lowZ), + 'lunit': obj.lunit}) return solid, cTubeName -def processGDMLElConeObject(obj) : + +def processGDMLElConeObject(obj): GDMLShared.trace('Elliptical Cone') elconeName = nameOfGDMLobject(obj) - solid = ET.Element('elcone',{'name': elconeName, \ - 'dx': str(obj.dx), \ - 'dy': str(obj.dy), \ - 'zcut' : str(obj.zcut), \ - 'zmax' : str(obj.zmax), \ - 'lunit' : str(obj.lunit)}) + solid = ET.SubElement(solids, 'elcone', {'name': elconeName, + 'dx': str(obj.dx), + 'dy': str(obj.dy), + 'zcut': str(obj.zcut), + 'zmax': str(obj.zmax), + 'lunit': str(obj.lunit)}) return solid, elconeName -def processGDMLEllipsoidObject(obj) : + +def processGDMLEllipsoidObject(obj): # Needs unique Name ellipsoidName = nameOfGDMLobject(obj) - solid = ET.Element('ellipsoid',{'name': ellipsoidName, \ - 'ax': str(obj.ax), \ - 'by': str(obj.by), \ - 'cz': str(obj.cz), \ - 'zcut1': str(obj.zcut1), \ - 'zcut2': str(obj.zcut2), \ - 'lunit' : obj.lunit}) + solid = ET.SubElement(solids, 'ellipsoid', {'name': ellipsoidName, + 'ax': str(obj.ax), + 'by': str(obj.by), + 'cz': str(obj.cz), + 'zcut1': str(obj.zcut1), + 'zcut2': str(obj.zcut2), + 'lunit': obj.lunit}) return solid, ellipsoidName -def processGDMLElTubeObject(obj) : + +def processGDMLElTubeObject(obj): # Needs unique Name # flag needed for boolean otherwise parse twice eltubeName = nameOfGDMLobject(obj) - solid = ET.Element('eltube',{'name': eltubeName, \ - 'dx': str(obj.dx), \ - 'dy': str(obj.dy), \ - 'dz': str(obj.dz), \ - 'lunit' : obj.lunit}) + solid = ET.SubElement(solids, 'eltube', {'name': eltubeName, + 'dx': str(obj.dx), + 'dy': str(obj.dy), + 'dz': str(obj.dz), + 'lunit': obj.lunit}) return solid, eltubeName -def processGDMLHypeObject(obj) : +def processGDMLHypeObject(obj): # Needs unique Name - # Remove leading GDMLTube_ from name on export - hypeName = nameOfGDMLobject(obj) - solid = ET.Element('hype',{'name': hypeName, \ - 'rmin': str(obj.rmin), \ - 'rmax': str(obj.rmax), \ - 'z': str(obj.z), \ - 'inst': str(obj.inst), \ - 'outst': str(obj.outst), \ - 'aunit': obj.aunit, \ - 'lunit' : obj.lunit}) - # modif 'mm' -> obj.lunit - return solid, hypeName - -def processGDMLParaboloidObject(obj) : + # Remove leading GDMLTube_ from name on export + hypeName = nameOfGDMLobject(obj) + solid = ET.SubElement(solids, 'hype', {'name': hypeName, + 'rmin': str(obj.rmin), + 'rmax': str(obj.rmax), + 'z': str(obj.z), + 'inst': str(obj.inst), + 'outst': str(obj.outst), + 'aunit': obj.aunit, + 'lunit': obj.lunit}) + # modif 'mm' -> obj.lunit + return solid, hypeName + + +def processGDMLParaboloidObject(obj): # Needs unique Name - # Remove leading GDMLTube_ from name on export - solidName = nameOfGDMLobject(obj) - solid = ET.Element('paraboloid',{'name': solidName, \ - 'rlo': str(obj.rlo), \ - 'rhi': str(obj.rhi), \ - 'dz': str(obj.dz), \ - 'lunit' : obj.lunit}) - # modif 'mm' -> obj.lunit - return solid, solidName - -def processGDMLOrbObject(obj) : + # Remove leading GDMLTube_ from name on export + solidName = nameOfGDMLobject(obj) + solid = ET.SubElement(solids, 'paraboloid', {'name': solidName, + 'rlo': str(obj.rlo), + 'rhi': str(obj.rhi), + 'dz': str(obj.dz), + 'lunit': obj.lunit}) + # modif 'mm' -> obj.lunit + return solid, solidName + + +def processGDMLOrbObject(obj): # Needs unique Name # flag needed for boolean otherwise parse twice orbName = nameOfGDMLobject(obj) - solid = ET.Element('orb',{'name': orbName, \ - 'r': str(obj.r), \ - 'lunit' : obj.lunit}) + solid = ET.SubElement(solids, 'orb', {'name': orbName, + 'r': str(obj.r), + 'lunit': obj.lunit}) return solid, orbName -def processGDMLParaObject(obj) : + +def processGDMLParaObject(obj): # Needs unique Name # flag needed for boolean otherwise parse twice paraName = nameOfGDMLobject(obj) - solid = ET.Element('para',{'name': paraName, \ - 'x': str(obj.x), \ - 'y': str(obj.y), \ - 'z': str(obj.z), \ - 'alpha':str(obj.alpha), \ - 'theta':str(obj.theta), \ - 'phi':str(obj.phi), \ - 'aunit':str(obj.aunit), \ - 'lunit' : obj.lunit}) + solid = ET.SubElement(solids, 'para', {'name': paraName, + 'x': str(obj.x), + 'y': str(obj.y), + 'z': str(obj.z), + 'alpha': str(obj.alpha), + 'theta': str(obj.theta), + 'phi': str(obj.phi), + 'aunit': str(obj.aunit), + 'lunit': obj.lunit}) return solid, paraName -def processGDMLPolyconeObject(obj) : + +def processGDMLPolyconeObject(obj): # Needs unique Name # flag needed for boolean otherwise parse twice - #polyconeName = 'Cone' + obj.Name + # polyconeName = 'Cone' + obj.Name polyconeName = nameOfGDMLobject(obj) - cone = ET.Element('polycone',{'name': polyconeName, \ - 'startphi': str(obj.startphi), \ - 'deltaphi': str(obj.deltaphi), \ - 'aunit': obj.aunit, \ - 'lunit' : obj.lunit }) - for zplane in obj.OutList : - ET.SubElement(cone, 'zplane',{'rmin': str(zplane.rmin), \ - 'rmax' : str(zplane.rmax), \ - 'z' : str(zplane.z)}) + cone = ET.SubElement(solids, 'polycone', {'name': polyconeName, + 'startphi': str(obj.startphi), + 'deltaphi': str(obj.deltaphi), + 'aunit': obj.aunit, + 'lunit': obj.lunit}) + for zplane in obj.OutList: + ET.SubElement(cone, 'zplane', {'rmin': str(zplane.rmin), + 'rmax': str(zplane.rmax), + 'z': str(zplane.z)}) return cone, polyconeName -def processGDMLGenericPolyconeObject(obj) : + +def processGDMLGenericPolyconeObject(obj): polyconeName = nameOfGDMLobject(obj) - cone = ET.Element('genericPolycone',{'name': polyconeName, \ - 'startphi': str(obj.startphi), \ - 'deltaphi': str(obj.deltaphi), \ - 'aunit': obj.aunit, \ - 'lunit' : obj.lunit }) - for rzpoint in obj.OutList : - ET.SubElement(cone, 'rzpoint',{'r': str(rzpoint.r), \ - 'z' : str(rzpoint.z)}) + cone = ET.SubElement(solids, 'genericPolycone', { + 'name': polyconeName, + 'startphi': str(obj.startphi), + 'deltaphi': str(obj.deltaphi), + 'aunit': obj.aunit, + 'lunit': obj.lunit}) + for rzpoint in obj.OutList: + ET.SubElement(cone, 'rzpoint', {'r': str(rzpoint.r), + 'z': str(rzpoint.z)}) return cone, polyconeName -def processGDMLGenericPolyhedraObject(obj) : + +def processGDMLGenericPolyhedraObject(obj): polyhedraName = nameOfGDMLobject(obj) - polyhedra = ET.Element('genericPolyhedra',{'name': polyhedraName, \ - 'startphi': str(obj.startphi), \ - 'deltaphi': str(obj.deltaphi), \ - 'numsides': str(obj.numsides), \ - 'aunit': obj.aunit, \ - 'lunit' : obj.lunit }) - for rzpoint in obj.OutList : - ET.SubElement(polyhedra, 'rzpoint',{'r': str(rzpoint.r), \ - 'z' : str(rzpoint.z)}) + polyhedra = ET.SubElement(solids, 'genericPolyhedra', { + 'name': polyhedraName, + 'startphi': str(obj.startphi), + 'deltaphi': str(obj.deltaphi), + 'numsides': str(obj.numsides), + 'aunit': obj.aunit, + 'lunit': obj.lunit}) + for rzpoint in obj.OutList: + ET.SubElement(polyhedra, 'rzpoint', {'r': str(rzpoint.r), + 'z': str(rzpoint.z)}) return polyhedra, polyhedraName -def processGDMLPolyhedraObject(obj) : + +def processGDMLPolyhedraObject(obj): # Needs unique Name # flag needed for boolean otherwise parse twice - #polyconeName = 'Cone' + obj.Name + # polyconeName = 'Cone' + obj.Name GDMLShared.trace('export Polyhedra') polyhedraName = nameOfGDMLobject(obj) - poly = ET.Element('polyhedra',{'name': polyhedraName, \ - 'startphi': str(obj.startphi), \ - 'deltaphi': str(obj.deltaphi), \ - 'numsides': str(obj.numsides), \ - 'aunit': obj.aunit, \ - 'lunit' : obj.lunit }) - for zplane in obj.OutList : - ET.SubElement(poly, 'zplane',{'rmin': str(zplane.rmin), \ - 'rmax' : str(zplane.rmax), \ - 'z' : str(zplane.z)}) + poly = ET.SubElement(solids, 'polyhedra', {'name': polyhedraName, + 'startphi': str(obj.startphi), + 'deltaphi': str(obj.deltaphi), + 'numsides': str(obj.numsides), + 'aunit': obj.aunit, + 'lunit': obj.lunit}) + for zplane in obj.OutList: + ET.SubElement(poly, 'zplane', {'rmin': str(zplane.rmin), + 'rmax': str(zplane.rmax), + 'z': str(zplane.z)}) return poly, polyhedraName -def processGDMLQuadObject(obj) : + +def processGDMLQuadObject(obj): GDMLShared.trace("GDMLQuadrangular") - ET.SubElement(solids,'quadrangular',{'vertex1': obj.v1, \ - 'vertex2': obj.v2, 'vertex3': obj.v3, 'vertex4': obj.v4, \ - 'type': obj.vtype}) - -def processGDMLSphereObject(obj) : + ET.SubElement(solids, 'quadrangular', {'vertex1': obj.v1, + 'vertex2': obj.v2, + 'vertex3': obj.v3, + 'vertex4': obj.v4, + 'type': obj.vtype}) + + +def processGDMLSphereObject(obj): # Needs unique Name sphereName = nameOfGDMLobject(obj) - - solid = ET.Element('sphere',{'name': sphereName, - 'rmin': str(obj.rmin), - 'rmax': str(obj.rmax), - 'startphi': str(obj.startphi), - 'deltaphi': str(obj.deltaphi), - 'starttheta': str(obj.starttheta), - 'deltatheta': str(obj.deltatheta), - 'aunit': obj.aunit, - 'lunit' : obj.lunit}) + + solid = ET.SubElement(solids, 'sphere', {'name': sphereName, + 'rmin': str(obj.rmin), + 'rmax': str(obj.rmax), + 'startphi': str(obj.startphi), + 'deltaphi': str(obj.deltaphi), + 'starttheta': str(obj.starttheta), + 'deltatheta': str(obj.deltatheta), + 'aunit': obj.aunit, + 'lunit': obj.lunit}) return solid, sphereName -def processGDMLTessellatedObject(obj) : + +def processGDMLTessellatedObject(obj): # Needs unique Name # Need to output unique define positions # Need to create set of positions - tessName = nameOfGDMLobject(obj) + tessName = nameOfGDMLobject(obj) # Use more readable version tessVname = tessName + '_' - #print(dir(obj)) + # print(dir(obj)) vertexHashcodeDict = {} - - tess = ET.Element('tessellated',{'name': tessName}) - for i, v in enumerate(obj.Shape.Vertexes) : - vertexHashcodeDict[v.hashCode()] = i - exportDefineVertex(tessVname,v,i) - - for f in obj.Shape.Faces : - #print(f'Normal at : {n} dot {dot} {clockWise}') + + tess = ET.SubElement(solids, 'tessellated', {'name': tessName}) + for i, v in enumerate(obj.Shape.Vertexes): + vertexHashcodeDict[v.hashCode()] = i + exportDefineVertex(tessVname, v, i) + + for f in obj.Shape.Faces: + # print(f'Normal at : {n} dot {dot} {clockWise}') vertexes = f.OuterWire.OrderedVertexes - if len(f.Edges) == 3 : - i0 = vertexHashcodeDict[vertexes[0].hashCode()] - i1 = vertexHashcodeDict[vertexes[1].hashCode()] - i2 = vertexHashcodeDict[vertexes[2].hashCode()] - ET.SubElement(tess,'triangular',{ \ - 'vertex1': tessVname+str(i0), \ - 'vertex2': tessVname+str(i1), \ - 'vertex3': tessVname+str(i2), \ - 'type':'ABSOLUTE'}) - elif len(f.Edges) == 4 : - i3 = vertexHashcodeDict[vertexes[3].hashCode()] - ET.SubElement(tess,'quadrangular',{ \ - 'vertex1': tessVname+str(i0), \ - 'vertex2': tessVname+str(i1), \ - 'vertex3': tessVname+str(i2), \ - 'vertex4': tessVname+str(i3), \ - 'type':'ABSOLUTE'}) + if len(f.Edges) == 3: + i0 = vertexHashcodeDict[vertexes[0].hashCode()] + i1 = vertexHashcodeDict[vertexes[1].hashCode()] + i2 = vertexHashcodeDict[vertexes[2].hashCode()] + ET.SubElement(tess, 'triangular', { + 'vertex1': tessVname+str(i0), + 'vertex2': tessVname+str(i1), + 'vertex3': tessVname+str(i2), + 'type': 'ABSOLUTE'}) + elif len(f.Edges) == 4: + i3 = vertexHashcodeDict[vertexes[3].hashCode()] + ET.SubElement(tess, 'quadrangular', { + 'vertex1': tessVname+str(i0), + 'vertex2': tessVname+str(i1), + 'vertex3': tessVname+str(i2), + 'vertex4': tessVname+str(i3), + 'type': 'ABSOLUTE'}) return tess, tessName -def processGDMLTetraObject(obj) : + +def processGDMLTetraObject(obj): tetraName = nameOfGDMLobject(obj) v1Name = tetraName + 'v1' v2Name = tetraName + 'v2' v3Name = tetraName + 'v3' v4Name = tetraName + 'v4' - exportDefine(v1Name,obj.v1) - exportDefine(v2Name,obj.v2) - exportDefine(v3Name,obj.v3) - exportDefine(v4Name,obj.v4) - - tetra = ET.Element('tet',{'name': tetraName, \ - 'vertex1': v1Name, \ - 'vertex2': v2Name, \ - 'vertex3': v3Name, \ - 'vertex4': v4Name}) - return tetra, tetraName - -def processGDMLTetrahedronObject(obj) : + exportDefine(v1Name, obj.v1) + exportDefine(v2Name, obj.v2) + exportDefine(v3Name, obj.v3) + exportDefine(v4Name, obj.v4) + + tetra = ET.SubElement(solids, 'tet', {'name': tetraName, + 'vertex1': v1Name, + 'vertex2': v2Name, + 'vertex3': v3Name, + 'vertex4': v4Name}) + return tetra, tetraName + + +def processGDMLTetrahedronObject(obj): global structure global solids tetrahedronName = nameOfGDMLobject(obj) - print('Len Tet'+str(len(obj.Proxy.Tetra))) + print('Len Tet' + str(len(obj.Proxy.Tetra))) count = 0 - for t in obj.Proxy.Tetra : - tetraName = 'Tetra_'+str(count) + for t in obj.Proxy.Tetra: + tetraName = 'Tetra_' + str(count) v1Name = tetraName + 'v1' v2Name = tetraName + 'v2' v3Name = tetraName + 'v3' v4Name = tetraName + 'v4' - exportDefine(v1Name,t[0]) - exportDefine(v2Name,t[1]) - exportDefine(v3Name,t[2]) - exportDefine(v4Name,t[3]) - tetsolid = ET.SubElement(solids,'tet',{'name': tetraName, \ - 'vertex1': v1Name, \ - 'vertex2': v2Name, \ - 'vertex3': v3Name, \ - 'vertex4': v4Name}) - lvName = 'LVtetra'+str(count) - lvol = ET.SubElement(structure,'volume', {'name':lvName}) + exportDefine(v1Name, t[0]) + exportDefine(v2Name, t[1]) + exportDefine(v3Name, t[2]) + exportDefine(v4Name, t[3]) + ET.SubElement(solids, 'tet', {'name': tetraName, + 'vertex1': v1Name, + 'vertex2': v2Name, + 'vertex3': v3Name, + 'vertex4': v4Name}) + lvName = 'LVtetra' + str(count) + lvol = ET.SubElement(structure, 'volume', {'name': lvName}) ET.SubElement(lvol, 'materialref', {'ref': obj.material}) ET.SubElement(lvol, 'solidref', {'ref': tetraName}) count += 1 # Now put out Assembly - assembly = ET.SubElement(structure, 'assembly',{'name':tetrahedronName}) + assembly = ET.SubElement(structure, 'assembly', {'name': tetrahedronName}) count = 0 - for t in obj.Proxy.Tetra : - lvName = 'LVtetra'+str(count) + for t in obj.Proxy.Tetra: + lvName = 'LVtetra' + str(count) physvol = ET.SubElement(assembly, 'physvol') - ET.SubElement(physvol, 'volumeref', {'ref':lvName}) - #ET.SubElement(physvol, 'position') - #ET.SubElement(physvol, 'rotation') + ET.SubElement(physvol, 'volumeref', {'ref': lvName}) + # ET.SubElement(physvol, 'position') + # ET.SubElement(physvol, 'rotation') count += 1 - return assembly, tetrahedronName + return assembly, tetrahedronName + -def processGDMLTorusObject(obj) : +def processGDMLTorusObject(obj): torusName = nameOfGDMLobject(obj) - torus = ET.Element('torus',{'name': torusName, - 'rmin': str(obj.rmin), \ - 'rmax': str(obj.rmax), \ - 'rtor': str(obj.rtor), \ - 'startphi': str(obj.startphi), \ - 'deltaphi': str(obj.deltaphi), \ - 'aunit': obj.aunit, \ - 'lunit': obj.lunit}) + print(f'Torus: {torusName}') + torus = ET.SubElement(solids, 'torus', {'name': torusName, + 'rmin': str(obj.rmin), + 'rmax': str(obj.rmax), + 'rtor': str(obj.rtor), + 'startphi': str(obj.startphi), + 'deltaphi': str(obj.deltaphi), + 'aunit': obj.aunit, + 'lunit': obj.lunit}) return torus, torusName -def processGDMLTrapObject(obj) : + +def processGDMLTrapObject(obj): # Needs unique Name trapName = nameOfGDMLobject(obj) - trap = ET.Element('trap',{'name': trapName, \ - 'z': str(obj.z), \ - 'theta': str(obj.theta), \ - 'phi': str(obj.phi), \ - 'x1': str(obj.x1), \ - 'x2': str(obj.x2), \ - 'x3': str(obj.x3), \ - 'x4': str(obj.x4), \ - 'y1': str(obj.y1), \ - 'y2': str(obj.y2), \ - 'alpha1': str(obj.alpha), \ - 'alpha2': str(obj.alpha), \ - 'aunit': obj.aunit, \ - 'lunit': obj.lunit}) + trap = ET.SubElement(solids, 'trap', {'name': trapName, + 'z': str(obj.z), + 'theta': str(obj.theta), + 'phi': str(obj.phi), + 'x1': str(obj.x1), + 'x2': str(obj.x2), + 'x3': str(obj.x3), + 'x4': str(obj.x4), + 'y1': str(obj.y1), + 'y2': str(obj.y2), + 'alpha1': str(obj.alpha), + 'alpha2': str(obj.alpha), + 'aunit': obj.aunit, + 'lunit': obj.lunit}) return trap, trapName -def processGDMLTrdObject(obj) : + +def processGDMLTrdObject(obj): # Needs unique Name trdName = nameOfGDMLobject(obj) - trd = ET.Element('trd',{'name': trdName, \ - 'z': str(obj.z), \ - 'x1': str(obj.x1), \ - 'x2': str(obj.x2), \ - 'y1': str(obj.y1), \ - 'y2': str(obj.y2), \ - 'lunit': obj.lunit}) + trd = ET.SubElement(solids, 'trd', {'name': trdName, + 'z': str(obj.z), + 'x1': str(obj.x1), + 'x2': str(obj.x2), + 'y1': str(obj.y1), + 'y2': str(obj.y2), + 'lunit': obj.lunit}) return trd, trdName -def processGDMLTriangle(obj) : - #print("Process GDML Triangle") - ET.SubElement(solids,'triangular',{'vertex1': obj.v1, \ - 'vertex2': obj.v2, 'vertex3': obj.v3, \ - 'type': obj.vtype}) +def processGDMLTriangle(obj): + # print("Process GDML Triangle") + ET.SubElement(solids, 'triangular', {'vertex1': obj.v1, + 'vertex2': obj.v2, 'vertex3': obj.v3, + 'type': obj.vtype}) -def processGDMLTubeObject(obj) : + +def processGDMLTubeObject(obj): # Needs unique Name # flag needed for boolean otherwise parse twice tubeName = nameOfGDMLobject(obj) - tube = ET.Element('tube',{'name': tubeName, \ - 'rmin': str(obj.rmin), \ - 'rmax': str(obj.rmax), \ - 'startphi': str(obj.startphi), \ - 'deltaphi': str(obj.deltaphi), \ - 'aunit': obj.aunit, - 'z': str(obj.z), \ - 'lunit' : obj.lunit}) + print(f'Tube: {tubeName}') + tube = ET.SubElement(solids, 'tube', {'name': tubeName, + 'rmin': str(obj.rmin), + 'rmax': str(obj.rmax), + 'startphi': str(obj.startphi), + 'deltaphi': str(obj.deltaphi), + 'aunit': obj.aunit, + 'z': str(obj.z), + 'lunit': obj.lunit}) return tube, tubeName -def processGDMLTwistedboxObject(obj) : - - solidName = nameOfGDMLobject(obj) - - solid = ET.Element('twistedbox',{'name': solidName, \ - 'PhiTwist': str(obj.PhiTwist), \ - 'x': str(obj.x), \ - 'y': str(obj.y), \ - 'z': str(obj.z), \ - 'aunit': str(obj.aunit), \ - 'lunit' : obj.lunit}) + +def processGDMLTwistedboxObject(obj): + + solidName = nameOfGDMLobject(obj) + + solid = ET.SubElement(solids, 'twistedbox', {'name': solidName, + 'PhiTwist': str(obj.PhiTwist), + 'x': str(obj.x), + 'y': str(obj.y), + 'z': str(obj.z), + 'aunit': str(obj.aunit), + 'lunit': obj.lunit}) return solid, solidName -def processGDMLTwistedtrdObject(obj) : + +def processGDMLTwistedtrdObject(obj): # Needs unique Name # flag needed for boolean otherwise parse twice solidName = nameOfGDMLobject(obj) - solid = ET.Element('twistedtrd',{'name': solidName, \ - 'PhiTwist':str(obj.PhiTwist), \ - 'x1': str(obj.x1), \ - 'x2': str(obj.x2), \ - 'y1': str(obj.y1), \ - 'y2': str(obj.y2), \ - 'z': str(obj.z), \ - 'aunit': str(obj.aunit), \ - 'lunit' : obj.lunit}) + solid = ET.SubElement(solids, 'twistedtrd', {'name': solidName, + 'PhiTwist': str(obj.PhiTwist), + 'x1': str(obj.x1), + 'x2': str(obj.x2), + 'y1': str(obj.y1), + 'y2': str(obj.y2), + 'z': str(obj.z), + 'aunit': str(obj.aunit), + 'lunit': obj.lunit}) return solid, solidName -def processGDMLTwistedtrapObject(obj) : + +def processGDMLTwistedtrapObject(obj): # Needs unique Name # flag needed for boolean otherwise parse twice solidName = nameOfGDMLobject(obj) - solid = ET.Element('twistedtrap',{'name': solidName, \ - 'PhiTwist':str(obj.PhiTwist), \ - 'x1': str(obj.x1), \ - 'x2': str(obj.x2), \ - 'y1': str(obj.y1), \ - 'y2': str(obj.y2), \ - 'x3': str(obj.x3), \ - 'x4': str(obj.x4), \ - 'z': str(obj.z), \ - 'Theta': str(obj.Theta), \ - 'Phi': str(obj.Phi), \ - 'Alph': str(obj.Alph), \ - 'aunit': str(obj.aunit), \ - 'lunit' : obj.lunit}) + solid = ET.SubElement(solids, 'twistedtrap', {'name': solidName, + 'PhiTwist': str(obj.PhiTwist), + 'x1': str(obj.x1), + 'x2': str(obj.x2), + 'y1': str(obj.y1), + 'y2': str(obj.y2), + 'x3': str(obj.x3), + 'x4': str(obj.x4), + 'z': str(obj.z), + 'Theta': str(obj.Theta), + 'Phi': str(obj.Phi), + 'Alph': str(obj.Alph), + 'aunit': str(obj.aunit), + 'lunit': obj.lunit}) return solid, solidName -def processGDMLTwistedtubsObject(obj) : + +def processGDMLTwistedtubsObject(obj): # Needs unique Name # flag needed for boolean otherwise parse twice solidName = nameOfGDMLobject(obj) - solid = ET.Element('twistedtubs',{'name': solidName, \ - 'twistedangle':str(obj.twistedangle), \ - 'endinnerrad': str(obj.endinnerrad), \ - 'endouterrad': str(obj.endouterrad), \ - 'zlen': str(obj.zlen), \ - 'phi': str(obj.phi), \ - 'aunit': str(obj.aunit), \ - 'lunit' : obj.lunit}) + solid = ET.SubElement(solids, 'twistedtubs', { + 'name': solidName, + 'twistedangle': str(obj.twistedangle), + 'endinnerrad': str(obj.endinnerrad), + 'endouterrad': str(obj.endouterrad), + 'zlen': str(obj.zlen), + 'phi': str(obj.phi), + 'aunit': str(obj.aunit), + 'lunit': obj.lunit}) return solid, solidName -def processGDMLXtruObject(obj) : + +def processGDMLXtruObject(obj): # Needs unique Name xtruName = nameOfGDMLobject(obj) - xtru = ET.Element('xtru',{'name': xtruName, \ - 'lunit' : obj.lunit}) - for items in obj.OutList : - if items.Type == 'twoDimVertex' : - ET.SubElement(xtru, 'twoDimVertex',{'x': str(items.x), \ - 'y': str(items.y)}) - if items.Type == 'section' : - ET.SubElement(xtru, 'section',{'zOrder': str(items.zOrder), \ - 'zPosition': str(items.zPosition), \ - 'xOffset' : str(items.xOffset), \ - 'yOffset' : str(items.yOffset), \ - 'scalingFactor' : str(items.scalingFactor)}) + xtru = ET.SubElement(solids, 'xtru', {'name': xtruName, + 'lunit': obj.lunit}) + for items in obj.OutList: + if items.Type == 'twoDimVertex': + ET.SubElement(xtru, 'twoDimVertex', {'x': str(items.x), + 'y': str(items.y)}) + if items.Type == 'section': + ET.SubElement(xtru, 'section', { + 'zOrder': str(items.zOrder), + 'zPosition': str(items.zPosition), + 'xOffset': str(items.xOffset), + 'yOffset': str(items.yOffset), + 'scalingFactor': str(items.scalingFactor)}) return xtru, xtruName -def processGDML2dVertex(obj) : - #print("Process 2d Vertex") - ET.SubElement(solids, 'twoDimVertex',{'x': obj.x, 'y': obj.y}) -def processIsotope(obj, item): # maybe part of material or element (common code) - if hasattr(obj,'Z') : - #print(dir(obj)) - item.set('Z',str(obj.Z)) +def processGDML2dVertex(obj): + # print("Process 2d Vertex") + ET.SubElement(solids, 'twoDimVertex', {'x': obj.x, 'y': obj.y}) - if hasattr(obj,'N') : - #print(dir(obj)) - item.set('N',str(obj.N)) - if hasattr(obj,'formula') : - #print(dir(obj)) - item.set('formula',str(obj.formula)) +def processIsotope(obj, item): # maybe part of material or element (common code) + if hasattr(obj, 'Z'): + # print(dir(obj)) + item.set('Z', str(obj.Z)) - if hasattr(obj,'unit') or hasattr(obj,'atom_value') or hasattr(obj,'value') : - atom = ET.SubElement(item,'atom') - - if hasattr(obj,'unit') : - atom.set('unit',str(obj.unit)) - - if hasattr(obj,'type') : - atom.set('unit',str(obj.type)) - - if hasattr(obj,'atom_value') : - atom.set('value',str(obj.atom_value)) + if hasattr(obj, 'N'): + # print(dir(obj)) + item.set('N', str(obj.N)) + + if hasattr(obj, 'formula'): + # print(dir(obj)) + item.set('formula', str(obj.formula)) - if hasattr(obj,'value') : - atom.set('value',str(obj.value)) + if hasattr(obj, 'unit') or hasattr(obj, 'atom_value') or \ + hasattr(obj, 'value'): + atom = ET.SubElement(item, 'atom') -def processMaterials() : + if hasattr(obj, 'unit'): + atom.set('unit', str(obj.unit)) + + if hasattr(obj, 'type'): + atom.set('unit', str(obj.type)) + + if hasattr(obj, 'atom_value'): + atom.set('value', str(obj.atom_value)) + + if hasattr(obj, 'value'): + atom.set('value', str(obj.value)) + + +def processMaterials(): print("\nProcess Materials") global materials - - for GName in ['Constants','Variables','Isotopes','Elements','Materials'] : + + for GName in ['Constants', 'Variables', + 'Isotopes', 'Elements', 'Materials']: Grp = FreeCAD.ActiveDocument.getObject(GName) - if Grp is not None : - #print(Grp.TypeId+" : "+Grp.Name) - print(Grp.Label) - if processGroup(Grp) == False : - break + if Grp is not None: + # print(Grp.TypeId+" : "+Grp.Name) + print(Grp.Label) + if processGroup(Grp) is False: + break -def processFractionsComposites(obj, item) : + +def processFractionsComposites(obj, item): # Fractions are used in Material and Elements - if isinstance(obj.Proxy,GDMLfraction) : - #print("GDML fraction :" + obj.Label) + if isinstance(obj.Proxy, GDMLfraction): + # print("GDML fraction :" + obj.Label) # need to strip number making it unique - ET.SubElement(item,'fraction',{'n': str(obj.n), \ - 'ref': nameFromLabel(obj.Label)}) + ET.SubElement(item, 'fraction', {'n': str(obj.n), + 'ref': nameFromLabel(obj.Label)}) + + if isinstance(obj.Proxy, GDMLcomposite): + # print("GDML Composite") + ET.SubElement(item, 'composite', {'n': str(obj.n), + 'ref': nameFromLabel(obj.Label)}) - if isinstance(obj.Proxy,GDMLcomposite) : - #print("GDML Composite") - ET.SubElement(item,'composite',{'n': str(obj.n), \ - 'ref': nameFromLabel(obj.Label)}) def createMaterials(group): global materials - for obj in group : + for obj in group: if obj.Label != 'Geant4': - item = ET.SubElement(materials,'material',{'name': \ - nameFromLabel(obj.Label)}) - - # Dunit & Dvalue must be first for Geant4 - if hasattr(obj,'Dunit') or hasattr(obj,'Dvalue') : - #print("Dunit or DValue") - D = ET.SubElement(item,'D') - if hasattr(obj,'Dunit') : - D.set('unit',str(obj.Dunit)) - - if hasattr(obj,'Dvalue') : - D.set('value',str(obj.Dvalue)) - - if hasattr(obj,'Tunit') and hasattr(obj,'Tvalue') : - ET.SubElement(item,'T',{'unit': obj.Tunit, \ - 'value': str(obj.Tvalue)}) - - if hasattr(obj,'MEEunit') : - ET.SubElement(item,'MEE',{'unit': obj.MEEunit, \ - 'value': str(obj.MEEvalue)}) - # process common options material / element - processIsotope(obj, item) - if len(obj.Group) > 0 : - for o in obj.Group : - processFractionsComposites(o,item) - -def createElements(group) : + item = ET.SubElement(materials, 'material', { + 'name': + nameFromLabel(obj.Label)}) + + # Dunit & Dvalue must be first for Geant4 + if hasattr(obj, 'Dunit') or hasattr(obj, 'Dvalue'): + # print("Dunit or DValue") + D = ET.SubElement(item, 'D') + if hasattr(obj, 'Dunit'): + D.set('unit', str(obj.Dunit)) + + if hasattr(obj, 'Dvalue'): + D.set('value', str(obj.Dvalue)) + + if hasattr(obj, 'Tunit') and hasattr(obj, 'Tvalue'): + ET.SubElement(item, 'T', {'unit': obj.Tunit, + 'value': str(obj.Tvalue)}) + + if hasattr(obj, 'MEEunit'): + ET.SubElement(item, 'MEE', {'unit': obj.MEEunit, + 'value': str(obj.MEEvalue)}) + # process common options material / element + processIsotope(obj, item) + if len(obj.Group) > 0: + for o in obj.Group: + processFractionsComposites(o, item) + + +def createElements(group): global materials - for obj in group : - #print(f'Element : {obj.Label}') - item = ET.SubElement(materials,'element',{'name': \ - nameFromLabel(obj.Label)}) + for obj in group: + # print(f'Element : {obj.Label}') + item = ET.SubElement(materials, 'element', { + 'name': nameFromLabel(obj.Label)}) # Common code IsoTope and Elements1 processIsotope(obj, item) - if len(obj.Group) > 0 : - for o in obj.Group : - processFractionsComposites(o,item) + if len(obj.Group) > 0: + for o in obj.Group: + processFractionsComposites(o, item) -def createConstants(group) : + +def createConstants(group): global define - for obj in group : - if isinstance(obj.Proxy,GDMLconstant) : - #print("GDML constant") - #print(dir(obj)) + for obj in group: + if isinstance(obj.Proxy, GDMLconstant): + # print("GDML constant") + # print(dir(obj)) + + ET.SubElement(define, 'constant', {'name': obj.Label, + 'value': obj.value}) - item = ET.SubElement(define,'constant',{'name': obj.Label, \ - 'value': obj.value }) -def createVariables(group) : +def createVariables(group): global define - for obj in group : - if isinstance(obj.Proxy,GDMLvariable) : - #print("GDML variable") - #print(dir(obj)) - - item = ET.SubElement(define,'variable',{'name': obj.Label, \ - 'value': obj.value }) -def createQuantities(group) : + for obj in group: + if isinstance(obj.Proxy, GDMLvariable): + # print("GDML variable") + # print(dir(obj)) + + ET.SubElement(define, 'variable', {'name': obj.Label, + 'value': obj.value}) + + +def createQuantities(group): global define - for obj in group : - if isinstance(obj.Proxy,GDMLquantity) : - #print("GDML quantity") - #print(dir(obj)) + for obj in group: + if isinstance(obj.Proxy, GDMLquantity): + # print("GDML quantity") + # print(dir(obj)) - item = ET.SubElement(define,'quantity',{'name': obj.Label, \ - 'type': obj.type, \ - 'unit': obj.unit, \ - 'value': obj.value }) + ET.SubElement(define, 'quantity', {'name': obj.Label, + 'type': obj.type, + 'unit': obj.unit, + 'value': obj.value}) -def createIsotopes(group) : + +def createIsotopes(group): global materials - for obj in group : - if isinstance(obj.Proxy,GDMLisotope) : - #print("GDML isotope") - #item = ET.SubElement(materials,'isotope',{'N': str(obj.N), \ - # 'Z': str(obj.Z), \ - # 'name' : obj.Label}) - #ET.SubElement(item,'atom',{'unit': obj.unit, \ - # 'value': str(obj.value)}) - item = ET.SubElement(materials,'isotope',{'name' : obj.Label}) - processIsotope(obj,item) - -def processGroup(obj) : + for obj in group: + if isinstance(obj.Proxy, GDMLisotope): + # print("GDML isotope") + # item = ET.SubElement(materials,'isotope',{'N': str(obj.N), \ + # 'Z': str(obj.Z), \ + # 'name' : obj.Label}) + # ET.SubElement(item,'atom',{'unit': obj.unit, \ + # 'value': str(obj.value)}) + item = ET.SubElement(materials, 'isotope', {'name': obj.Label}) + processIsotope(obj, item) + + +def processGroup(obj): print('Process Group '+obj.Label) - #print(obj.TypeId) - #print(obj.Group) + # print(obj.TypeId) + # print(obj.Group) # if hasattr(obj,'Group') : - #return - if hasattr(obj,'Group') : - #print(" Object List : "+obj.Label) - #print(obj) - while switch(obj.Name) : - if case("Constants") : - #print("Constants") + # return + if hasattr(obj, 'Group'): + # print(" Object List : "+obj.Label) + # print(obj) + while switch(obj.Name): + if case("Constants"): + # print("Constants") createConstants(obj.Group) break - if case("Variables") : - #print("Variables") + if case("Variables"): + # print("Variables") createVariables(obj.Group) break - if case("Quantities") : - #print("Quantities") + if case("Quantities"): + # print("Quantities") createQuantities(obj.Group) break - if case("Isotopes") : - #print("Isotopes") + if case("Isotopes"): + # print("Isotopes") createIsotopes(obj.Group) break - - if case("Elements") : - #print("Elements") + + if case("Elements"): + # print("Elements") createElements(obj.Group) break - - if case("Materials") : + + if case("Materials"): print("Materials") createMaterials(obj.Group) break - if case("Geant4") : + if case("Geant4"): # Do not export predefine in Geant4 print("Geant4") break -def processGDMLSolid(obj) : + +def processGDMLSolid(obj): # Deal with GDML Solids first # Deal with FC Objects that convert - #print(dir(obj)) - #print(dir(obj.Proxy)) + # print(dir(obj)) + # print(dir(obj.Proxy)) print(obj.Proxy.Type) - while switch(obj.Proxy.Type) : - if case("GDMLArb8") : - #print(" GDMLArb8") - solid, name = processGDMLArb8Object(obj) - break - - if case("GDMLBox") : - #print(" GDMLBox") - solid, name = processGDMLBoxObject(obj) - break - - if case("GDMLCone") : - #print(" GDMLCone") - solid, name = processGDMLConeObject(obj) - break - - if case("GDMLcutTube") : - #print(" GDMLcutTube") - solid, name = processGDMLCutTubeObject(obj) - break - - if case("GDMLElCone") : - #print(" GDMLElCone") - solid, name = processGDMLElConeObject(obj) - break - - if case("GDMLEllipsoid") : - #print(" GDMLEllipsoid") - solid, name = processGDMLEllipsoidObject(obj) - break - - if case("GDMLElTube") : - #print(" GDMLElTube") - solid, name = processGDMLElTubeObject(obj) - break - - if case("GDMLHype") : - #print(" GDMLHype") - solid, name = processGDMLHypeObject(obj) - break - - if case("GDMLOrb") : - #print(" GDMLOrb") - solid, name = processGDMLOrbObject(obj) - break - - if case("GDMLPara") : - #print(" GDMLPara") - solid, name = processGDMLParaObject(obj) - break - - if case("GDMLParaboloid") : - #print(" GDMLParaboloid") - solid, name = processGDMLParaboloidObject(obj) - break - - if case("GDMLPolycone") : - #print(" GDMLPolycone") - solid, name = processGDMLPolyconeObject(obj) - break - - if case("GDMLGenericPolycone") : - #print(" GDMLGenericPolycone") - solid, name = processGDMLGenericPolyconeObject(obj) - break - - if case("GDMLPolyhedra") : - #print(" GDMLPolyhedra") - solid, name = processGDMLPolyhedraObject(obj) - break - - if case("GDMLGenericPolyhedra") : - #print(" GDMLPolyhedra") - solid, name = processGDMLGenericPolyhedraObject(obj) - break - - if case("GDMLSphere") : - #print(" GDMLSphere") - solid, name = processGDMLSphereObject(obj) - break - - if case("GDMLTessellated") : - #print(" GDMLTessellated") - solid, name = processGDMLTessellatedObject(obj) - break - - if case("GDMLGmshTessellated") : - #print(" GDMLGmshTessellated") - # export GDMLTessellated & GDMLGmshTesssellated should be the same - solid, name = processGDMLTessellatedObject(obj) - break - - if case("GDMLTetra") : - #print(" GDMLTetra") - solid, name = processGDMLTetraObject(obj) - break - - if case("GDMLTetrahedron") : - print(" GDMLTetrahedron") - solid, name = processGDMLTetrahedronObject(obj) - break - - if case("GDMLTorus") : - print(" GDMLTorus") - solid, name = processGDMLTorusObject(obj) - break - - if case("GDMLTrap") : - #print(" GDMLTrap") - solid, name = processGDMLTrapObject(obj) - break - - if case("GDMLTrd") : - #print(" GDMLTrd") - solid, name = processGDMLTrdObject(obj) - break - - if case("GDMLTube") : - #print(" GDMLTube") - solid, name = processGDMLTubeObject(obj) - break - - if case("GDMLTwistedbox") : - #print(" GDMLTwistedbox") - solid, name = processGDMLTwistedboxObject(obj) - break - - if case("GDMLTwistedtrap") : - #print(" GDMLTwistedtrap") - solid, name = processGDMLTwistedtrapObject(obj) - break - - if case("GDMLTwistedtrd") : - #print(" GDMLTwistedbox") - solid, name = processGDMLTwistedtrdObject(obj) - break - - if case("GDMLTwistedtubs") : - #print(" GDMLTwistedbox") - solid, name = processGDMLTwistedtubsObject(obj) - break - - if case("GDMLXtru") : - #print(" GDMLXtru") - solid, name = processGDMLXtruObject(obj) - break - - print("Not yet Handled") - break - solids.insert(0,solid) - -def processMuNod(xmlelem, name) : - node = ET.SubElement(xmlelem,'multiUnionNode',{'name' : name}) + while switch(obj.Proxy.Type): + if case("GDMLArb8"): + # print(" GDMLArb8") + return(processGDMLArb8Object(obj)) + + if case("GDMLBox"): + # print(" GDMLBox") + return(processGDMLBoxObject(obj)) + + if case("GDMLCone"): + # print(" GDMLCone") + return(processGDMLConeObject(obj)) + + if case("GDMLcutTube"): + # print(" GDMLcutTube") + return(processGDMLCutTubeObject(obj)) + + if case("GDMLElCone"): + # print(" GDMLElCone") + return(processGDMLElConeObject(obj)) + + if case("GDMLEllipsoid"): + # print(" GDMLEllipsoid") + return(processGDMLEllipsoidObject(obj)) + + if case("GDMLElTube"): + # print(" GDMLElTube") + return(processGDMLElTubeObject(obj)) + + if case("GDMLHype"): + # print(" GDMLHype") + return(processGDMLHypeObject(obj)) + + if case("GDMLOrb"): + # print(" GDMLOrb") + return(processGDMLOrbObject(obj)) + + if case("GDMLPara"): + # print(" GDMLPara") + return(processGDMLParaObject(obj)) + + if case("GDMLParaboloid"): + # print(" GDMLParaboloid") + return(processGDMLParaboloidObject(obj)) + + if case("GDMLPolycone"): + # print(" GDMLPolycone") + return(processGDMLPolyconeObject(obj)) + + if case("GDMLGenericPolycone"): + # print(" GDMLGenericPolycone") + return(processGDMLGenericPolyconeObject(obj)) + + if case("GDMLPolyhedra"): + # print(" GDMLPolyhedra") + return(processGDMLPolyhedraObject(obj)) + + if case("GDMLGenericPolyhedra"): + # print(" GDMLPolyhedra") + return(processGDMLGenericPolyhedraObject(obj)) + + if case("GDMLSphere"): + # print(" GDMLSphere") + return(processGDMLSphereObject(obj)) + + if case("GDMLTessellated"): + # print(" GDMLTessellated") + ret = processGDMLTessellatedObject(obj) + return ret + + if case("GDMLGmshTessellated"): + # print(" GDMLGmshTessellated") + # export GDMLTessellated & GDMLGmshTesssellated should be the same + return(processGDMLTessellatedObject(obj)) + + if case("GDMLTetra"): + # print(" GDMLTetra") + return(processGDMLTetraObject(obj)) + + if case("GDMLTetrahedron"): + print(" GDMLTetrahedron") + return(processGDMLTetrahedronObject(obj)) + + if case("GDMLTorus"): + print(" GDMLTorus") + return(processGDMLTorusObject(obj)) + + if case("GDMLTrap"): + # print(" GDMLTrap") + return(processGDMLTrapObject(obj)) + + if case("GDMLTrd"): + # print(" GDMLTrd") + return(processGDMLTrdObject(obj)) + + if case("GDMLTube"): + # print(" GDMLTube") + return(processGDMLTubeObject(obj)) + + if case("GDMLTwistedbox"): + # print(" GDMLTwistedbox") + return(processGDMLTwistedboxObject(obj)) + + if case("GDMLTwistedtrap"): + # print(" GDMLTwistedtrap") + return(processGDMLTwistedtrapObject(obj)) + + if case("GDMLTwistedtrd"): + # print(" GDMLTwistedbox") + return(processGDMLTwistedtrdObject(obj)) + + if case("GDMLTwistedtubs"): + # print(" GDMLTwistedbox") + return(processGDMLTwistedtubsObject(obj)) + + if case("GDMLXtru"): + # print(" GDMLXtru") + return(processGDMLXtruObject(obj)) + + print("Not yet Handled") + break + + +def processSolid(obj, addVolsFlag): + # export solid & return Name + # Needs to deal with Boolean solids + # separate from Boolean Objects + # return count, solidxml, solidName + # print('Process Solid') + while switch(obj.TypeId): + + if case("Part::FeaturePython"): + # print(" Python Feature") + # if hasattr(obj.Proxy, 'Type') : + # #print(obj.Proxy.Type) + # return(processGDMLSolid(obj)) + solidxml, solidName = processGDMLSolid(obj) + return solidxml, solidName + # + # Now deal with Boolean solids + # Note handle different from Bookean Objects + # that need volume, physvol etc + # i.e. just details needed to be added to Solids + # + if case("Part::MultiFuse"): + GDMLShared.trace("Multifuse - multiunion") + # test and fix + solidName = 'MultiFuse' + obj.Name + # First add solids in list before reference + print('Output Solids') + for sub in obj.OutList: + processSolid(sub, False) + GDMLShared.trace('Output Solids Complete') + multUnion = ET.SubElement(solids, 'multiUnion', { + 'name': solidName}) + num = 1 + + for sub in obj.OutList: + GDMLShared.trace(sub.Name) + node = processMuNod(multUnion, 'node-'+str(num)) + ET.SubElement(node, 'solid', {'ref': sub.Name}) + processPosition(sub, node) + processRotation(sub, node) + num += 1 + + GDMLShared.trace('Return MultiUnion') + # return idx + num + return solidName + + if case("Part::MultiCommon"): + print(" Multi Common / intersection") + print(" Not available in GDML") + exit(-3) + break + + # Now deal with objects that map to GDML solids + # + if case("Part::Box"): + print(" Box") + return(processBoxObject(obj, addVolsFlag)) + break + + if case("Part::Cylinder"): + print(" Cylinder") + return(processCylinderObject(obj, addVolsFlag)) + break + + if case("Part::Cone"): + print(" Cone") + return(processConeObject(obj, addVolsFlag)) + break + + if case("Part::Sphere"): + print(" Sphere") + return(processSphereObject(obj, addVolsFlag)) + break + + print(f'Part : {obj.Label}') + print(f'TypeId : {obj.TypeId}') + + +def processMuNod(xmlelem, name): + node = ET.SubElement(xmlelem, 'multiUnionNode', {'name': name}) return node + import collections from itertools import islice -def consume(iterator) : - next(islice(iterator,2,2), None) -def getXmlVolume(volObj) : +def consume(iterator): + next(islice(iterator, 2, 2), None) + + +def getXmlVolume(volObj): global structure - if volObj is None : - return None + if volObj is None: + return None xmlvol = structure.find("volume[@name='%s']" % volObj.Label) - if xmlvol is None : - print(volObj.Label+' Not Found') + if xmlvol is None: + print(volObj.Label+' Not Found') return xmlvol -def getCount(obj) : - GDMLShared.trace('get Count : '+obj.Name) - if hasattr(obj,'Tool') : - GDMLShared.trace('Has tool - check Base') - baseCnt = getCount(obj.Base) - toolCnt = getCount(obj.Tool) - GDMLShared.trace('Count is : '+str(baseCnt + toolCnt)) - return (baseCnt + toolCnt) - else : - return 1 -def getMaterial(obj) : +def getBooleanCount(obj): + GDMLShared.trace('get Count : ' + obj.Name) + if hasattr(obj, 'Tool'): + GDMLShared.trace('Has tool - check Base') + baseCnt = getBooleanCount(obj.Base) + toolCnt = getBooleanCount(obj.Tool) + GDMLShared.trace('Count is : ' + str(baseCnt + toolCnt)) + return (baseCnt + toolCnt) + else: + return 0 + + +def getMaterial(obj): GDMLShared.trace('get Material : '+obj.Label) - if hasattr(obj,'material') : - return obj.material - if hasattr(obj,'Tool') : - GDMLShared.trace('Has tool - check Base') - material = getMaterial(obj.Base) - return material - else : - return None + if hasattr(obj, 'material'): + return obj.material + if hasattr(obj, 'Tool'): + GDMLShared.trace('Has tool - check Base') + material = getMaterial(obj.Base) + return material + else: + return None -def printObjectInfo(xmlVol, volName, xmlParent, parentName) : + +''' +def printObjectInfo(xmlVol, volName, xmlParent, parentName): print("Process Object : "+obj.Label+' Type '+obj.TypeId) if xmlVol is not None : xmlstr = ET.tostring(xmlVol) @@ -1591,266 +1794,359 @@ def printObjectInfo(xmlVol, volName, xmlParent, parentName) : else : xmlstr = 'None' print('Parent : '+str(parentName)+' : '+str(xmlstr)) +''' + -def processObject(obj, xmlVol, volName, xmlParent, parentName) : +def isBoolean(obj): + id = obj.TypeId + return (id == "Part::Cut" or id == "Part::Fuse" or + id == "Part::Common") + + +def boolOperation(obj): + opsDict = {"Part::Cut": 'subtraction', + "Part::Fuse": 'union', + "Part::Common": 'intersection'} + if obj.TypeId in opsDict: + return opsDict[obj.TypeId] + else: + print(f'Boolean type {obj.TypId} not handled yet') + return None + + +def processBooleanObject(obj, xmlVol, volName, xmlParent, parentName): + ''' + In FreeCAD doc booleans that are themselves composed of other booleans + are listed in sequence, eg: + topBool: + Base: Nonbool_0 + Tool: bool1: + Base: bool2: + Base: Nonbool_1 + Tool: Nonbool_2 + Tool: bool3: + Base: Nonbool_3 + Tool: Nonbool_4 + In the gdml file, boolean solids must always refer to PREVIOUSLY defined + solids. So the last booleans must be written first: + + + + + + + + + + + The code below first builds the list of booleans in order: + [topBool, bool1, bool2, bool3] + + Then outputs them to gdml in reverse order. + In the process of scanning for booleans, the Nonbooleans are exported + + ''' + GDMLShared.trace('Process Boolean Object') + + boolsList = [obj] # list of booleans that are part of obj + # dynamic list the is used to figure out when we've iterated over all subobjects + # that are booleans + tmpList = [obj] + ref1 = {} # first solid reference of boolean + ref2 = {} # second solid reference of boolean + count = 1 # number of solids under this boolean + while(len(tmpList) > 0): + obj1 = tmpList.pop() + if isBoolean(obj1.Base): + tmpList.append(obj1.Base) + boolsList.append(obj1.Base) + ref1[obj1] = obj1.Base.Label + else: + solidxml, solidName = processSolid(obj1.Base, False) + ref1[obj1] = solidName + + if isBoolean(obj1.Tool): + tmpList.append(obj1.Tool) + boolsList.append(obj1.Tool) + ref2[obj1] = obj1.Tool.Label + else: + solidxml, solidName = processSolid(obj1.Tool, False) + ref2[obj1] = solidName + + count += len(obj1.Base.OutList) + len(obj1.Tool.OutList) + + # Now tmpList is empty and boolsList has list of all booleans + for obj1 in reversed(boolsList): + operation = boolOperation(obj1) + if operation is None: + continue + solidName = obj1.Label + boolXML = ET.SubElement(solids, str(operation), { + 'name': solidName}) + ET.SubElement(boolXML, 'first', {'ref': ref1[obj1]}) + ET.SubElement(boolXML, 'second', {'ref': ref2[obj1]}) + # process position & rotationt + processPosition(obj1.Tool, boolXML) + # For booleans, gdml want actual rotation, not reverse + # processRotation export negative of rotation angle(s) + # This is ugly way of NOT reversing angle: + angle = obj1.Tool.Placement.Rotation.Angle + obj1.Tool.Placement.Rotation.Angle = -angle + processRotation(obj1.Tool, boolXML) + obj1.Tool.Placement.Rotation.Angle = angle + + # The material and colour are those of the Base of the boolean + # the solidName is that of the LAST solid in the above loop. Since + # the boolList is traversed in reverse order, this is the topmost boolean + addVolRef(xmlVol, volName, obj) + + return 2 + count + + +def exportCone(name, radius, height): + cylEl = ET.SubElement(solids, 'cone', {'name': name, + 'rmin1': '0', + 'rmax1': str(radius), + 'rmin2': '0', + 'rmax2': str(radius), + 'z': str(height), + 'startphi': '0', + 'deltaphi': '360', + 'aunit': 'deg', 'lunit': 'mm'}) + return cylEl + + +def processObject(cnt, idx, obj, xmlVol, volName, + xmlParent, parentName): + # cnt - number of GDML objects in Part/Volume + # If cnt == 1 - No need to create Volume use Part.Label & No PhysVol + # idx - index into OutList + # obj - This object # xmlVol - xmlVol # xmlParent - xmlParent Volume # parentName - Parent Name - #ET.ElementTree(gdml).write("test9a", 'utf-8', True) - #if obj.Label[:12] != 'NOT_Expanded' : - # printObjectInfo(xmlVol, volName, xmlParent, parentName) - #print('structure : '+str(xmlstr)) - GDMLShared.trace('Process Object : '+obj.Label) - while switch(obj.TypeId) : - - if case("App::Part") : - if obj.Label[:12] != 'NOT_Expanded' : - if hasattr(obj,'InList') : - parentName = obj.InList[0].Label - else : - parentName = None + GDMLShared.trace('Process Object : ' + obj.Label) + while switch(obj.TypeId): + + if case("App::Part"): + if obj.Label[:12] != 'NOT_Expanded': + if hasattr(obj, 'InList'): + parentName = obj.InList[0].Label + else: + parentName = None print(obj.Label) - #print(dir(obj)) + # print(dir(obj)) processVolAssem(obj, xmlVol, volName, True) - return - - if case("PartDesign::Body") : - print("Part Design Body - ignoring") - return - - if case("App::Origin") : - #print("App Origin") - return - - #if case("App::GeoFeature") : - # #print("App GeoFeature") - # return - - #if case("App::Line") : - # #print("App Line") - # return - - #f case("App::Plane") : - # #print("App Plane") - # return - - # Okay this is duplicate Volume cpynum > 1 - parent is a Volume - if case("App::Link") : - print('App::Link :'+obj.Label) - #print(dir(obj)) - print(obj.LinkedObject.Label) - addPhysVolPlacement(obj,xmlVol,obj.LinkedObject.Label) - return - - if case("Part::Cut") : - GDMLShared.trace("Cut - subtraction") - solidName = obj.Label - subtract = ET.SubElement(solids,'subtraction',{'name': solidName }) - ET.SubElement(subtract,'first', {'ref': nameOfGDMLobject(obj.Base)}) - ET.SubElement(subtract,'second',{'ref': nameOfGDMLobject(obj.Tool)}) - #solids.insert(0,subtract) - # process position & rotation ? - processPosition(obj.Tool,subtract) - processRotation(obj.Tool,subtract) - return obj - - if case("Part::Fuse") : - GDMLShared.trace("Fuse - union") - print("Fuse - union") - #print(dir(obj)) - #print(len(obj.InList)) - #print('InList') - #for o in obj.InList : - # print(o.Label) - #print(len(obj.OutList)) - #print('OutList') - #for o in obj.OutList : - # print(o.Label) - solidName = obj.Label - union = ET.SubElement(solids,'union',{'name': solidName }) - ET.SubElement(union,'first', {'ref': nameOfGDMLobject(obj.Base)}) - ET.SubElement(union,'second',{'ref': nameOfGDMLobject(obj.Tool)}) - print(f'Insert union : {solidName}') - #solids.insert(0,union) - # process position & rotation ? - processPosition(obj.Tool,union) - processRotation(obj.Tool,union) - return obj - - if case("Part::Common") : - GDMLShared.trace("Common - Intersection") - solidName = obj.Label - intersect = ET.SubElement(solids,'subtraction',{'name': solidName }) - ET.SubElement(intersect,'first', {'ref': nameOfGDMLobject(obj.Base)}) - ET.SubElement(intersect,'second',{'ref': nameOfGDMLobject(obj.Tool)}) - #solids.insert(0,intersect) - # process position & rotation ? - processPosition(obj.Tool,intersect) - processRotation(obj.Tool,intersect) - return obj - - if case("Part::MultiFuse") : - GDMLShared.trace(" Multifuse") - print(" Multifuse") - # test and fix - solidName = obj.Label - #boolCount = getCount(obj.Base) - #GDMLShared.trace('Count : '+str(boolCount)) - #addVolRef(xmlVol, volName, solidName, obj.Base) - #testAddPhysVol(obj, xmlParent, parentName) - # First add solids in list before reference - print('Output Solids') - for sub in obj.OutList: - #processSolid(sub,False) - processGDMLSolid(sub) - print('Output Solids Complete') - multUnion = ET.SubElement(solids,'multiUnion',{'name': solidName }) - num = 1 - - for sub in obj.OutList: - print(sub.Name) - node = processMuNod(multUnion, 'node-'+str(num)) - ET.SubElement(node,'solid',{'ref':sub.Name}) - processPosition(sub,node) - processRotation(sub,node) - num += 1 - - return obj - - if case("Part::MultiCommon") : - print(" Multi Common / intersection") - print(" Not available in GDML") - exit(-3) - break - - if case("Mesh::Feature") : - print(" Mesh Feature") - # test and Fix - #processMesh(obj, obj.Mesh, obj.Label) - #addVolRef(xmlVol, volName, solidName, obj) - #print('Need to add code for Mesh Material and colour') - #testAddPhysVol(obj, xmlParent, parentName): - # return solid ??? - return - - if case("Part::FeaturePython"): - GDMLShared.trace(" Python Feature") - if GDMLShared.getTrace == True : - if hasattr(obj.Proxy, 'Type') : - print(obj.Proxy.Type) - #if cnt > 1 : - # volName = 'LV-'+solidName - # xmlVol = insertXMLvolume(volName) - #addVolRef(xmlVol, volName, solidName, obj) - #if asmFlg == True : # Don't add physvol if GDML object in an assembly - # testAddPhysVol(obj, xmlParent, parentName) - processGDMLSolid(obj) - return obj - - # Same as Part::Feature but no position - if case("App::FeaturePython") : - print("App::FeaturePython") - # Following not needed as handled bu Outlist on Tessellated - #if isinstance(obj.Proxy, GDMLQuadrangular) : - # return(processGDMLQuadObject(obj, addVolsFlag)) - # break + return idx + 1 + + if case("PartDesign::Body"): + print("Part Design Body - ignoring") + return idx + 1 + + if case("Sketcher::SketchObject"): + print(f'Sketch {obj.Label}') + if hasattr(obj, 'InList'): + print(f'Has InList {obj.InList}') + for subObj in obj.InList: + print(f'subobj typeid {subObj.TypeId}') + if subObj.TypeId == "Part::Extrusion": + exportExtrusion.processExtrudedSketch(subObj, obj, xmlVol) + return idx + 1 + + if case("Part::Extrusion"): + print("Part Extrusion - Handle in Sketch") + return idx + 1 + + if case("App::Origin"): + # print("App Origin") + return idx + 1 + + # Okay this is duplicate Volume cpynum > 1 - parent is a Volume + if case("App::Link"): + print('App::Link :' + obj.Label) + # print(dir(obj)) + print(obj.LinkedObject.Label) + addPhysVolPlacement(obj, xmlVol, obj.LinkedObject.Label) + return idx + 1 + + if case("Part::Cut"): + GDMLShared.trace("Cut - subtraction") + retval = idx + processBooleanObject(obj, xmlVol, volName, + xmlParent, parentName) + return retval + + if case("Part::Fuse"): + GDMLShared.trace("Fuse - union") + retval = idx + processBooleanObject(obj, xmlVol, volName, + xmlParent, parentName) + print(f'retval {retval}') + return retval + + if case("Part::Common"): + GDMLShared.trace("Common - Intersection") + retval = idx + processBooleanObject(obj, xmlVol, volName, + xmlParent, parentName) + return retval + + if case("Part::MultiFuse"): + GDMLShared.trace(" Multifuse") + print(" Multifuse") + # test and fix + solidName = obj.Label + print('Output Solids') + for sub in obj.OutList: + processGDMLSolid(sub) + print('Output Solids Complete') + multUnion = ET.SubElement(solids, 'multiUnion', { + 'name': solidName}) + num = 1 + + for sub in obj.OutList: + print(sub.Name) + node = processMuNod(multUnion, 'node-' + str(num)) + ET.SubElement(node, 'solid', {'ref': sub.Name}) + processPosition(sub, node) + processRotation(sub, node) + num += 1 + + return idx + num + + if case("Part::MultiCommon"): + print(" Multi Common / intersection") + print(" Not available in GDML") + exit(-3) + + if case("Mesh::Feature"): + print(" Mesh Feature") + # test and Fix + # processMesh(obj, obj.Mesh, obj.Label) + # addVolRef(xmlVol, volName, solidName, obj) + # print('Need to add code for Mesh Material and colour') + # testAddPhysVol(obj, xmlParent, parentName): + # return solid ??? + return idx + 1 + + if case("Part::FeaturePython"): + GDMLShared.trace(" Python Feature") + print(f'FeaturePython: {obj.Label}') + if GDMLShared.getTrace is True: + if hasattr(obj.Proxy, 'Type'): + print(obj.Proxy.Type) + solidxml, solidName = processSolid(obj, True) + if cnt > 1: + volName = 'LV-'+solidName + xmlVol = insertXMLvolume(volName) + addVolRef(xmlVol, volName, obj, solidName) + return idx + 1 + + # Same as Part::Feature but no position + if case("App::FeaturePython"): + print("App::FeaturePython") + # Following not needed as handled bu Outlist on Tessellated + # if isinstance(obj.Proxy, GDMLQuadrangular) : + # return(processGDMLQuadObject(obj, addVolsFlag)) + # break - #if isinstance(obj.Proxy, GDMLTriangular) : - # return(processGDMLTriangleObject(obj, addVolsFlag)) - # break + # if isinstance(obj.Proxy, GDMLTriangular) : + # return(processGDMLTriangleObject(obj, addVolsFlag)) + # break - # Following not needed as handled bu Outlist on Xtru + # Following not needed as handled bu Outlist on Xtru - #if isinstance(obj.Proxy, GDML2dVertex) : - # return(processGDML2dVertObject(obj, addVolsFlag)) - # break + # if isinstance(obj.Proxy, GDML2dVertex) : + # return(processGDML2dVertObject(obj, addVolsFlag)) + # break - #if isinstance(obj.Proxy, GDMLSection) : - # return(processGDMLSection(obj, addVolsFlag)) - # break - return - - # - # Now deal with objects that map to GDML solids - # - if case("Part::Box") : - print(" Box") - #return(processBoxObject(obj, addVolsFlag)) - processBoxObject(obj, addVolsFlag) - #testAddPhysVol(obj, xmlParent, parentName) - return - - if case("Part::Cylinder") : - print(" Cylinder") - #return(processCylinderObject(obj, addVolsFlag)) - processCylinderObject(obj, addVolsFlag) - #testAddPhysVol(obj, xmlParent, parentName) - return - - if case("Part::Cone") : - print(" Cone") - #return(processConeObject(obj, addVolsFlag)) - processConeObject(obj, addVolsFlag) - #testAddPhysVol(obj, xmlParent, parentName) - return - - if case("Part::Sphere") : - print(" Sphere") - #return(processSphereObject(obj, addVolsFlag)) - processSphereObject(obj, addVolsFlag) - #testAddPhysVol(obj, xmlParent, parentName) - return - - # Not a Solid that translated to GDML solid - # Dropped through so treat object as a shape - # Need to check obj has attribute Shape - # Create tessellated solid - # - #return(processObjectShape(obj, addVolsFlag)) - print("Convert FreeCAD shape to GDML Tessellated") - print(obj.TypeId) - return - - if hasattr(obj,'Shape') : - if obj.Shape.isValid() : - #return(processObjectShape(obj)) - processObjectShape(obj) - #testAddPhysVol(obj, xmlParent, parentName) - return + # if isinstance(obj.Proxy, GDMLSection) : + # return(processGDMLSection(obj, addVolsFlag)) + # break + return idx + 1 + + # + # Now deal with objects that map to GDML solids + # + if case("Part::Box"): + print(" Box") + # return(processBoxObject(obj, addVolsFlag)) + processBoxObject(obj, True) + # testAddPhysVol(obj, xmlParent, parentName) + return idx + 1 + + if case("Part::Cylinder"): + print(" Cylinder") + # return(processCylinderObject(obj, addVolsFlag)) + processCylinderObject(obj, True) + # testAddPhysVol(obj, xmlParent, parentName) + return idx + 1 + + if case("Part::Cone"): + print(" Cone") + # return(processConeObject(obj, addVolsFlag)) + processConeObject(obj, True) + # testAddPhysVol(obj, xmlParent, parentName) + return idx + 1 + + if case("Part::Sphere"): + print(" Sphere") + # return(processSphereObject(obj, addVolsFlag)) + processSphereObject(obj, True) + # testAddPhysVol(obj, xmlParent, parentName) + return idx + 1 + + # Not a Solid that translated to GDML solid + # Dropped through so treat object as a shape + # Need to check obj has attribute Shape + # Create tessellated solid + # + # return(processObjectShape(obj, addVolsFlag)) + # print("Convert FreeCAD shape to GDML Tessellated") + print(f"Object {obj.Label} Type : {obj.TypeId} Not yet handled") + print(obj.TypeId) + return idx + 1 + + if hasattr(obj, 'Shape'): + if obj.Shape.isValid(): + # return(processObjectShape(obj)) + processObjectShape(obj) + # testAddPhysVol(obj, xmlParent, parentName) + return idx + 1 + def insertXMLvolume(name): # Insert at beginning for sub volumes - GDMLShared.trace('insert xml volume : '+name) - elem = ET.Element('volume',{'name': name}) + GDMLShared.trace('insert xml volume : ' + name) + elem = ET.Element('volume', {'name': name}) global structure - structure.insert(0,elem) + structure.insert(0, elem) return elem -def insertXMLvolObj(obj) : - #name = cleanVolName(obj, obj.Label) + +def insertXMLvolObj(obj): + # name = cleanVolName(obj, obj.Label) name = obj.Label return insertXMLvolume(name) + def insertXMLassembly(name): # Insert at beginning for sub volumes - GDMLShared.trace('insert xml assembly : '+name) - elem = ET.Element('assembly',{'name': name}) + GDMLShared.trace('insert xml assembly : ' + name) + elem = ET.Element('assembly', {'name': name}) global structure - structure.insert(0,elem) + structure.insert(0, elem) return elem -def insertXMLassemObj(obj) : - #name = cleanVolName(obj, obj.Label) + +def insertXMLassemObj(obj): + # name = cleanVolName(obj, obj.Label) name = obj.Label return insertXMLassembly(name) -def createXMLvol(name): - return ET.SubElement(structure,'volume',{'name': name}) +def createXMLvol(name): + return ET.SubElement(structure, 'volume', {'name': name}) - volName = cleanVolName(vol, vol.Label) -def processAssembly(vol, xmlVol, xmlParent, parentName, addVolsFlag) : +def processAssembly(vol, xmlVol, xmlParent, parentName, addVolsFlag): # vol - Volume Object # xmlVol - xml of this volume # xmlParent - xml of this volumes Paretnt @@ -1858,39 +2154,51 @@ def processAssembly(vol, xmlVol, xmlParent, parentName, addVolsFlag) : # So for s in list is not so good # type 1 straight GDML type = 2 for GEMC # xmlVol could be created dummy volume - #GDMLShared.setTrace(True) + GDMLShared.setTrace(True) volName = vol.Label - #volName = cleanVolName(vol, vol.Label) + # volName = cleanVolName(vol, vol.Label) GDMLShared.trace('Process Assembly : '+volName) - if GDMLShared.getTrace() == True : - printVolumeInfo(vol, xmlVol, xmlParent, parentName) - if hasattr(vol,'OutList') : - for obj in vol.OutList : - if obj.TypeId == 'App::Part' : - processVolAssem(obj, xmlVol, volName, addVolsFlag) - - elif obj.TypeId == 'App::Link' : + # if GDMLShared.getTrace() == True : + # printVolumeInfo(vol, xmlVol, xmlParent, parentName) + if hasattr(vol, 'OutList'): + print('Has OutList') + for obj in vol.OutList: + if obj.TypeId == 'App::Part': + processVolAssem(obj, xmlVol, volName, addVolsFlag) + + elif obj.TypeId == 'App::Link': print('Process Link') - #objName = cleanVolName(obj, obj.Label) - addPhysVolPlacement(obj,xmlVol,obj.LinkedObject.Label) + # objName = cleanVolName(obj, obj.Label) + addPhysVolPlacement(obj, xmlVol, obj.LinkedObject.Label) - addPhysVolPlacement(vol,xmlParent,volName) + elif obj.TypeId == "Sketcher::SketchObject": + print(f'Sketch {obj.Label}') + if hasattr(obj, 'InList'): + print(f'Has InList {obj.InList}') + for subObj in obj.InList: + print(f'subobj typeid {subObj.TypeId}') + if subObj.TypeId == "Part::Extrusion": + exportExtrusion.processExtrudedSketch(subObj, + obj, xmlVol) + addPhysVolPlacement(vol, xmlParent, volName) -def printVolumeInfo(vol, xmlVol, xmlParent, parentName) : - if xmlVol is not None : - xmlstr = ET.tostring(xmlVol) - else : - xmlstr ='None' + +def printVolumeInfo(vol, xmlVol, xmlParent, parentName): + if xmlVol is not None: + xmlstr = ET.tostring(xmlVol) + else: + xmlstr = 'None' print(xmlstr) - GDMLShared.trace(' '+vol.Label+ ' - '+str(xmlstr)) - if xmlParent is not None : - xmlstr = ET.tostring(xmlParent) - else : - xmlstr ='None' - GDMLShared.trace(' Parent : '+str(parentName)+' : '+ str(xmlstr)) + GDMLShared.trace(' '+vol.Label + ' - ' + str(xmlstr)) + if xmlParent is not None: + xmlstr = ET.tostring(xmlParent) + else: + xmlstr = 'None' + GDMLShared.trace(' Parent : ' + str(parentName) + ' : ' + str(xmlstr)) -def processVolume(vol, xmlVol, xmlParent, parentName, addVolsFlag) : + +def processVolume(vol, xmlVol, xmlParent, parentName, addVolsFlag): # vol - Volume Object # xmlVol - xml of this volume # xmlParent - xml of this volumes Paretnt @@ -1900,179 +2208,208 @@ def processVolume(vol, xmlVol, xmlParent, parentName, addVolsFlag) : # xmlVol could be created dummy volume volName = vol.Label print(f'Process Volume : {volName}') - #volName = cleanVolName(vol, vol.Label) - if GDMLShared.getTrace() == True : - GDMLShared.trace('Process Volume : '+volName) - printVolumeInfo(vol, xmlVol, xmlParent, parentName) - - if hasattr(vol,'SensDet') : - if vol.SensDet is not None : - print('Volume : '+volName) - print('SensDet : '+vol.SensDet) - ET.SubElement(xmlVol,'auxiliary',{'auxtype':'SensDet', \ - 'auxvalue' : vol.SensDet}) - if hasattr(vol,'OutList') : - GDMLShared.trace('OutList length : '+str(len(vol.OutList))) - gdmlObj = None - for obj in vol.OutList : - robj = processObject(obj,xmlVol, volName, xmlParent, parentName) - if robj is not None : - gdmlObj = robj - addVolRef(xmlVol, volName, gdmlObj) - addPhysVolPlacement(vol,xmlParent,volName) - -def processVolAssem(vol, xmlParent, parentName, addVolsFlag) : + # volName = cleanVolName(vol, vol.Label) + if GDMLShared.getTrace() is True: + GDMLShared.trace('Process Volume : ' + volName) + printVolumeInfo(vol, xmlVol, xmlParent, parentName) + + if hasattr(vol, 'SensDet'): + if vol.SensDet is not None: + print('Volume : ' + volName) + print('SensDet : ' + vol.SensDet) + ET.SubElement(xmlVol, 'auxiliary', {'auxtype': 'SensDet', + 'auxvalue': vol.SensDet}) + idx = 0 + cnt = 0 + if hasattr(vol, 'OutList'): + num = len(vol.OutList) + cnt = countGDMLObj(vol.OutList) + # Depending on how the Parts were constructed, the + # the order of items in the OutList may not reflect + # the tree hierarchy in view. If we have bolleans of + # booleans, we must start with the top most boolean + # code below gets the boolean that has the largest + # number of sub booleans + maxCount = 0 + rootBool = None + for obj in vol.OutList: + boolCount = getBooleanCount(obj) + if boolCount > maxCount: + maxCount = boolCount + rootBool = obj + + if rootBool is not None: + processObject(cnt, idx, rootBool, + xmlVol, volName, xmlParent, parentName) + else: + GDMLShared.trace('OutList length : ' + str(num)) + while idx < num: + print(f'idx {idx} {vol.OutList[idx].TypeId}') + idx = processObject(cnt, idx, vol.OutList[idx], + xmlVol, volName, xmlParent, parentName) + addPhysVolPlacement(vol, xmlParent, volName) + + +def processVolAssem(vol, xmlParent, parentName, addVolsFlag): # vol - Volume Object # xmlVol - xml of this volume # xmlParent - xml of this volumes Paretnt # xmlVol could be created dummy volume print('process volasm '+vol.Label) volName = vol.Label - #volName = cleanVolName(vol, vol.Label) - if hasattr(vol,'OutList') : # Do we have Objects ? - cnt = countGDMLObj(vol.OutList) - print('VolAsm - count '+str(cnt)) - if cnt > 0 : - newXmlVol = insertXMLvolume(volName) - processVolume(vol, newXmlVol, xmlParent, parentName, addVolsFlag) - else : - newXmlVol = insertXMLassembly(volName) - processAssembly(vol, newXmlVol, xmlParent, parentName, addVolsFlag) - - #addPhysVolPlacement(vol,xmlParent,volName) - #elif obj.TypeId == 'App::Link' : - # addPhysVolPlacement(obj,xmlVol,objName) - -def createWorldVol(volName) : + # volName = cleanVolName(vol, vol.Label) + if hasattr(vol, 'OutList'): # Do we have Objects ? + cnt = countGDMLObj(vol.OutList) + print('VolAsm - count ' + str(cnt)) + if cnt > 0: + newXmlVol = insertXMLvolume(volName) + processVolume(vol, newXmlVol, xmlParent, parentName, addVolsFlag) + else: + newXmlVol = insertXMLassembly(volName) + processAssembly(vol, newXmlVol, xmlParent, parentName, addVolsFlag) + + # addPhysVolPlacement(vol,xmlParent,volName) + # elif obj.TypeId == 'App::Link' : + # addPhysVolPlacement(obj,xmlVol,objName) + + +def createWorldVol(volName): print("Need to create Dummy Volume and World Box ") bbox = FreeCAD.BoundBox() boxName = defineWorldBox(bbox) - worldVol = ET.SubElement(structure,'volume',{'name': volName}) + worldVol = ET.SubElement(structure, 'volume', {'name': volName}) print("Need to FIX !!!! To use defined gas") - ET.SubElement(worldVol, 'materialref',{'ref': 'G4_Galactic'}) - ET.SubElement(worldVol, 'solidref',{'ref': boxName}) - ET.SubElement(gxml,'volume',{'name': volName, 'material':'G4_AIR'}) + ET.SubElement(worldVol, 'materialref', {'ref': 'G4_Galactic'}) + ET.SubElement(worldVol, 'solidref', {'ref': boxName}) + ET.SubElement(gxml, 'volume', {'name': volName, 'material': 'G4_AIR'}) return worldVol + def countGDMLObj(objList): - # Return position of first GDML object and count - #print('countGDMLObj') + # Return counts GDML objects exportables + # #rint('countGDMLObj') GDMLShared.trace('countGDMLObj') - count = 0 - #print(range(len(objList))) - for idx in range(len(objList)) : - #print('idx : '+str(idx)) + gcount = 0 + # print(range(len(objList))) + for idx in range(len(objList)): + # print('idx : '+str(idx)) obj = objList[idx] - if obj.TypeId == 'Part::FeaturePython' : - count += 1 + if obj.TypeId == 'Part::FeaturePython': + gcount += 1 if obj.TypeId == 'Part::Cut' \ or obj.TypeId == 'Part::Fuse' \ - or obj.TypeId == 'Part::Common' : - count -= 1 - #print('countGDMLObj - Count : '+str(count)) - GDMLShared.trace('countGDMLObj - Count : '+str(count)) - return count - -def checkGDMLstructure(objList) : - # Should be + or obj.TypeId == 'Part::Common': + gcount -= 1 + # print('countGDMLObj - Count : '+str(gcount)) + GDMLShared.trace('countGDMLObj - gdml : ' + str(gcount)) + return gcount + + +def checkGDMLstructure(objList): + # Should be # World Vol - App::Part # App::Origin # GDML Object GDMLShared.trace('check GDML structure') GDMLShared.trace(objList) - #print(objList) + # print(objList) cnt = countGDMLObj(objList) - if cnt > 1 : # More than one GDML Object need to insert Dummy - return False - if cnt == 1 and len(objList) == 2 : # Just a single GDML obj insert Dummy - return False + if cnt > 1: # More than one GDML Object need to insert Dummy + return False + if cnt == 1 and len(objList) == 2: # Just a single GDML obj insert Dummy + return False return True - #if len(objList) < 3 : - # return False - #if objList[0].TypeId != 'App::Origin' \ - # or objList[2].TypeId != 'App::Part' : + # if len(objList) < 3 : + # return False + # if objList[0].TypeId != 'App::Origin' \ + # or objList[2].TypeId != 'App::Part' : # return False - #return True + # return True -def locateXMLvol(vol) : + +def locateXMLvol(vol): global structure xmlVol = structure.find("volume[@name='%s']" % vol.Label) return xmlVol -def exportWorldVol(vol, fileExt) : + +def exportWorldVol(vol, fileExt): global WorldVOL WorldVOL = vol.Label - if fileExt != '.xml' : - print('Export World Process Volume : '+vol.Label) - GDMLShared.trace('Export Word Process Volume'+vol.Label) - ET.SubElement(setup,'world',{'ref':vol.Label}) - - if checkGDMLstructure(vol.OutList) == False : - GDMLShared.trace('Insert Dummy Volume') - xmlVol = createXMLvol('dummy') - xmlParent = createWorldVol(vol.Label) - parentName = vol.Label - addPhysVol(xmlParent,'dummy') - else : - GDMLShared.trace('Valid Structure') - xmlParent = None - parentName = None - else : - xmlParent = None - parentName = None - if hasattr(vol,'OutList') : - #print(vol.OutList) - cnt = countGDMLObj(vol.OutList) - #print('Root GDML Count '+str(cnt)) - if cnt > 0 : - xmlVol = insertXMLvolume(vol.Label) - processVolume(vol, xmlVol, xmlParent, parentName, False) - else : - xmlVol = insertXMLassembly(vol.Label) - processAssembly(vol, xmlVol, xmlParent, parentName, False) + if fileExt != '.xml': + print('Export World Process Volume : ' + vol.Label) + GDMLShared.trace('Export Word Process Volume' + vol.Label) + ET.SubElement(setup, 'world', {'ref': vol.Label}) + + if checkGDMLstructure(vol.OutList) is False: + GDMLShared.trace('Insert Dummy Volume') + xmlVol = createXMLvol('dummy') + xmlParent = createWorldVol(vol.Label) + parentName = vol.Label + addPhysVol(xmlParent, 'dummy') + else: + GDMLShared.trace('Valid Structure') + xmlParent = None + parentName = None + else: + xmlParent = None + parentName = None + if hasattr(vol, 'OutList'): + # print(vol.OutList) + cnt = countGDMLObj(vol.OutList) + print('Root GDML Count ' + str(cnt)) + if cnt > 0: + xmlVol = insertXMLvolume(vol.Label) + processVolume(vol, xmlVol, xmlParent, parentName, False) + else: + xmlVol = insertXMLassembly(vol.Label) + processAssembly(vol, xmlVol, xmlParent, parentName, False) -def exportElementAsXML(dirPath, fileName, flag, elemName, elem) : +def exportElementAsXML(dirPath, fileName, flag, elemName, elem): # gdml is a global global gdml, docString, importStr - if elem is not None : - #xmlElem = ET.Element('xml') - #xmlElem.append(elem) - #indent(xmlElem) - if flag == True : - filename = fileName+'-'+elemName+'.xml' - else : - filename = elemName+'.xml' - #ET.ElementTree(xmlElem).write(os.path.join(dirPath,filename)) - ET.ElementTree(elem).write(os.path.join(dirPath,filename)) - docString += '\n' - gdml.append(ET.Entity(elemName)) - -def exportGDMLstructure(dirPath, fileName) : + if elem is not None: + # xmlElem = ET.Element('xml') + # xmlElem.append(elem) + # indent(xmlElem) + if flag is True: + filename = fileName+'-' + elemName + '.xml' + else: + filename = elemName + '.xml' + # ET.ElementTree(xmlElem).write(os.path.join(dirPath,filename)) + ET.ElementTree(elem).write(os.path.join(dirPath, filename)) + docString += '\n' + gdml.append(ET.Entity(elemName)) + + +def exportGDMLstructure(dirPath, fileName): global gdml, docString, importStr print("Write GDML structure to Directory") gdml = initGDML() docString = '\n\n' - #print(docString) - #print(len(docString)) - #gdml = ET.fromstring(docString.encode("UTF-8")) + # print(docString) + # print(len(docString)) + # gdml = ET.fromstring(docString.encode("UTF-8")) indent(gdml) - ET.ElementTree(gdml).write(os.path.join(dirPath,fileName+'.gdml'), \ - doctype=docString.encode('UTF-8')) + ET.ElementTree(gdml).write(os.path.join(dirPath, fileName+'.gdml'), + doctype=docString.encode('UTF-8')) print("GDML file structure written") -def exportGDML(first, filepath, fileExt) : + +def exportGDML(first, filepath, fileExt): from . import GDMLShared + global zOrder - #GDMLShared.setTrace(True) + # GDMLShared.setTrace(True) GDMLShared.trace('exportGDML') print("====> Start GDML Export 1.6") print('File extension : '+fileExt) @@ -2081,265 +2418,269 @@ def exportGDML(first, filepath, fileExt) : zOrder = 1 processMaterials() exportWorldVol(first, fileExt) - # format & write GDML file - #xmlstr = ET.tostring(structure) - #print('Structure : '+str(xmlstr)) - if fileExt == '.gdml' : - indent(gdml) - print("Write to gdml file") - #ET.ElementTree(gdml).write(filepath, 'utf-8', True) - ET.ElementTree(gdml).write(filepath,xml_declaration=True) - #ET.ElementTree(gdml).write(filepath, pretty_print=True, \ - #xml_declaration=True) - print("GDML file written") - - if fileExt == '.GDML' : - filePath = os.path.split(filepath) - print('Input File Path : '+filepath) - fileName = os.path.splitext(filePath[1])[0] - print('File Name : '+fileName) - dirPath = os.path.join(filePath[0],fileName) - print('Directory Path : '+dirPath) - if os.path.exists(dirPath) == False : - if os.path.isdir(dirPath) == False : - os.makedirs(dirPath) - if os.path.isdir(dirPath) == True : - exportGDMLstructure(dirPath, fileName) - else : - print('Invalid Path') - # change to Qt Warning - - if fileExt == '.xml' : - xmlElem = ET.Element('xml') - xmlElem.append(solids) - xmlElem.append(structure) - indent(xmlElem) - ET.ElementTree(xmlElem).write(filepath) - print("XML file written") - -def exportGDMLworld(first,filepath,fileExt) : - if filepath.lower().endswith('.gdml') : - # GDML Export - print('GDML Export') - #if hasattr(first,'InList') : - # print(len(first.InList)) - - if hasattr(first,'OutList') : - cnt = countGDMLObj(first.OutList) - GDMLShared.trace('Count : '+str(cnt)) - if cnt > 1 : - from .GDMLQtDialogs import showInvalidWorldVol - showInvalidWorldVol() - - else : - exportGDML(first,filepath,fileExt) - -def hexInt(f) : + # format & write GDML file + # xmlstr = ET.tostring(structure) + # print('Structure : '+str(xmlstr)) + if fileExt == '.gdml': + indent(gdml) + print("Write to gdml file") + # ET.ElementTree(gdml).write(filepath, 'utf-8', True) + ET.ElementTree(gdml).write(filepath, xml_declaration=True) + # ET.ElementTree(gdml).write(filepath, pretty_print=True, \ + # xml_declaration=True) + print("GDML file written") + + if fileExt == '.GDML': + filePath = os.path.split(filepath) + print('Input File Path : '+filepath) + fileName = os.path.splitext(filePath[1])[0] + print('File Name : '+fileName) + dirPath = os.path.join(filePath[0], fileName) + print('Directory Path : '+dirPath) + if os.path.exists(dirPath) is False: + if os.path.isdir(dirPath) is False: + os.makedirs(dirPath) + if os.path.isdir(dirPath) is True: + exportGDMLstructure(dirPath, fileName) + else: + print('Invalid Path') + # change to Qt Warning + + if fileExt == '.xml': + xmlElem = ET.Element('xml') + xmlElem.append(solids) + xmlElem.append(structure) + indent(xmlElem) + ET.ElementTree(xmlElem).write(filepath) + print("XML file written") + + +def exportGDMLworld(first, filepath, fileExt): + if filepath.lower().endswith('.gdml'): + # GDML Export + print('GDML Export') + # if hasattr(first,'InList') : + # print(len(first.InList)) + + if hasattr(first, 'OutList'): + cnt = countGDMLObj(first.OutList) + GDMLShared.trace('Count : ' + str(cnt)) + if cnt > 1: + from .GDMLQtDialogs import showInvalidWorldVol + showInvalidWorldVol() + else: + exportGDML(first, filepath, fileExt) + + +def hexInt(f): return hex(int(f*255))[2:].zfill(2) + def formatPosition(pos): - s = str(pos[0])+'*mm '+str(pos[1])+'*mm '+str(pos[2])+'*mm' + s = str(pos[0]) + '*mm ' + str(pos[1]) + '*mm ' +str(pos[2]) + '*mm' print(s) return s -def scanForStl(first, gxml, path, flag ): - - from .GDMLColourMap import lookupColour - - # if flag == True ignore Parts that convert - print('scanForStl') - print(first.Name+' : '+first.Label+' : '+first.TypeId) - while switch(first.TypeId) : - - if case("App::Origin") : - #print("App Origin") - return - break - - if case("App::GeoFeature") : - #print("App GeoFeature") - return - break - - if case("App::Line") : - #print("App Line") - return - break - - if case("App::Plane") : - #print("App Plane") - return - break - - break - - if flag == True : - # - # Now deal with objects that map to GDML solids - # - while switch(first.TypeId) : - if case("Part::FeaturePython") : - return - break - if case("Part::Box") : - print(" Box") +def scanForStl(first, gxml, path, flag): + + from .GDMLColourMap import lookupColour + + # if flag == True ignore Parts that convert + print('scanForStl') + print(first.Name+' : '+first.Label+' : '+first.TypeId) + while switch(first.TypeId): + + if case("App::Origin"): + # print("App Origin") return - break - if case("Part::Cylinder") : - print(" Cylinder") + if case("App::GeoFeature"): + # print("App GeoFeature") return - break - if case("Part::Cone") : - print(" Cone") + if case("App::Line"): + # print("App Line") return - break - if case("Part::Sphere") : - print(" Sphere") + if case("App::Plane"): + # print("App Plane") return + + break + + if flag is True: + # + # Now deal with objects that map to GDML solids + # + while switch(first.TypeId): + if case("Part::FeaturePython"): + return + + if case("Part::Box"): + print(" Box") + return + + if case("Part::Cylinder"): + print(" Cylinder") + return + + if case("Part::Cone"): + print(" Cone") + return + + if case("Part::Sphere"): + print(" Sphere") + return + break - break - - # Deal with Booleans which will have Tool - if hasattr(first,'Tool') : - print(first.TypeId) - scanForStl(first.Base, gxml, path, flag) - scanForStl(first.Tool, gxml, path, flag) - - if hasattr(first,'OutList') : - for obj in first.OutList : - scanForStl(obj, gxml, path, flag) - - if first.TypeId != 'App::Part' : - if hasattr(first,'Shape') : - print('Write out stl') - print('===> Name : '+first.Name+' Label : '+first.Label+' \ - Type :'+first.TypeId+' : '+str(hasattr(first,'Shape'))) - newpath = os.path.join(path,first.Label+'.stl') - print('Exporting : '+newpath) - first.Shape.exportStl(newpath) - # Set Defaults - colHex = 'ff0000' - mat = 'G4Si' - if hasattr(first.ViewObject,'ShapeColor') : - #print(dir(first)) - col = first.ViewObject.ShapeColor - colHex = hexInt(col[0]) + hexInt(col[1]) + hexInt(col[2]) - print('===> Colour '+str(col) + ' '+colHex) - mat = lookupColour(col) - print('Material : '+mat) - if hasattr(first,'Placement') : - print(first.Placement.Base) - pos = formatPosition(first.Placement.Base) - ET.SubElement(gxml,'volume',{'name':first.Label, \ - 'color': colHex, 'material':mat, 'position': pos}) - -def exportGXML(first, path, flag) : + # Deal with Booleans which will have Tool + if hasattr(first, 'Tool'): + print(first.TypeId) + scanForStl(first.Base, gxml, path, flag) + scanForStl(first.Tool, gxml, path, flag) + + if hasattr(first, 'OutList'): + for obj in first.OutList: + scanForStl(obj, gxml, path, flag) + + if first.TypeId != 'App::Part': + if hasattr(first, 'Shape'): + print('Write out stl') + print('===> Name : '+first.Name+' Label : '+first.Label+' \ + Type :'+first.TypeId+' : '+str(hasattr(first, 'Shape'))) + newpath = os.path.join(path, first.Label + '.stl') + print('Exporting : ' + newpath) + first.Shape.exportStl(newpath) + # Set Defaults + colHex = 'ff0000' + mat = 'G4Si' + if hasattr(first.ViewObject, 'ShapeColor'): + # print(dir(first)) + col = first.ViewObject.ShapeColor + colHex = hexInt(col[0]) + hexInt(col[1]) + hexInt(col[2]) + print('===> Colour '+str(col) + ' '+colHex) + mat = lookupColour(col) + print('Material : '+mat) + if hasattr(first, 'Placement'): + print(first.Placement.Base) + pos = formatPosition(first.Placement.Base) + ET.SubElement(gxml, 'volume', {'name': first.Label, + 'color': colHex, + 'material': mat, + 'position': pos}) + + +def exportGXML(first, path, flag): print('Path : '+path) - #basename = 'target_'+os.path.basename(path) + # basename = 'target_'+os.path.basename(path) gxml = ET.Element('gxml') print('ScanForStl') scanForStl(first, gxml, path, flag) - # format & write gxml file + # format & write gxml file indent(gxml) print("Write to gxml file") - #ET.ElementTree(gxml).write(os.path.join(path,basename+'.gxml')) - ET.ElementTree(gxml).write(os.path.join(path,'target_cad.gxml')) + # ET.ElementTree(gxml).write(os.path.join(path,basename+'.gxml')) + ET.ElementTree(gxml).write(os.path.join(path, 'target_cad.gxml')) print("gxml file written") -def exportMaterials(first,filename) : - if filename.lower().endswith('.xml') : - print('Export Materials to XML file : '+filename) - xml = ET.Element('xml') - global define - define = ET.SubElement(xml,'define') - global materials - materials = ET.SubElement(xml,'materials') - processMaterials() - indent(xml) - ET.ElementTree(xml).write(filename) - else : - print('File extension must be xml') -def create_gcard(path, flag) : +def exportMaterials(first, filename): + if filename.lower().endswith('.xml'): + print('Export Materials to XML file : '+filename) + xml = ET.Element('xml') + global define + define = ET.SubElement(xml, 'define') + global materials + materials = ET.SubElement(xml, 'materials') + processMaterials() + indent(xml) + ET.ElementTree(xml).write(filename) + else: + print('File extension must be xml') + + +def create_gcard(path, flag): basename = os.path.basename(path) print('Create gcard : '+basename) print('Path : '+path) gcard = ET.Element('gcard') - ET.SubElement(gcard,'detector',{'name':'target_cad','factory':'CAD'}) - if flag == True : - ET.SubElement(gcard,'detector',{'name':'target_gdml','factory':'GDML'}) + ET.SubElement(gcard, 'detector', {'name': 'target_cad', 'factory': 'CAD'}) + if flag is True: + ET.SubElement(gcard, 'detector', { + 'name': 'target_gdml', 'factory': 'GDML'}) indent(gcard) - path = os.path.join(path,basename+'.gcard') + path = os.path.join(path, basename + '.gcard') ET.ElementTree(gcard).write(path) -def checkDirectory(path) : + +def checkDirectory(path): if not os.path.exists(path): - print('Creating Directory : '+path) - os.mkdir(path) + print('Creating Directory : ' + path) + os.mkdir(path) -def exportGEMC(first, path, flag) : + +def exportGEMC(first, path, flag): # flag = True GEMC - GDML # flag = False just CAD global gxml print('Export GEMC') - #basename = os.path.basename(path) + # basename = os.path.basename(path) print(path) print(flag) checkDirectory(path) # Create CAD directory - cadPath = os.path.join(path,'cad') + cadPath = os.path.join(path, 'cad') checkDirectory(cadPath) # Create gcard create_gcard(path, flag) exportGXML(first, cadPath, flag) - if flag == True : - print('Create GDML directory') - gdmlPath = os.path.join(path,'gdml') - checkDirectory(gdmlPath) - #gdmlFilePath = os.path.join(gdmlPath,basename+'.gdml') - gdmlFilePath = os.path.join(gdmlPath,'target_gdml.gdml') - exportGDML(first, gdmlFilePath,'gdml') - #newpath = os.path.join(gdmlPath,basename+'.gxml') - newpath = os.path.join(gdmlPath,'target_gdml.gxml') - indent(gxml) - ET.ElementTree(gxml).write(newpath) - -def export(exportList,filepath) : + if flag is True: + print('Create GDML directory') + gdmlPath = os.path.join(path, 'gdml') + checkDirectory(gdmlPath) + # gdmlFilePath = os.path.join(gdmlPath,basename+'.gdml') + gdmlFilePath = os.path.join(gdmlPath, 'target_gdml.gdml') + exportGDML(first, gdmlFilePath, 'gdml') + # newpath = os.path.join(gdmlPath,basename+'.gxml') + newpath = os.path.join(gdmlPath, 'target_gdml.gxml') + indent(gxml) + ET.ElementTree(gxml).write(newpath) + + +def export(exportList, filepath): "called when FreeCAD exports a file" - + first = exportList[0] print(f'Export Volume: {first.Label}') - + import os path, fileExt = os.path.splitext(filepath) print('filepath : '+path) print('file extension : '+fileExt) - if fileExt.lower() == '.gdml' : - if first.TypeId == "App::Part" : - exportGDMLworld(first,filepath,fileExt) - - elif first.Label == "Materials" : - exportMaterials(first,filepath) - - else : - print("Needs to be a Part for export") - from PySide import QtGui - QtGui.QMessageBox.critical(None,'Need to select a Part for export', \ - 'Press OK') - - elif fileExt.lower == '.xml' : - print('Export XML structure & solids') - exportGDML(first,filepath,'.xml') - - if fileExt == '.gemc' : - exportGEMC(first, path, False) - - elif fileExt == '.GEMC' : - exportGEMC(first, path, True) + if fileExt.lower() == '.gdml': + if first.TypeId == "App::Part": + exportGDMLworld(first, filepath, fileExt) + + elif first.Label == "Materials": + exportMaterials(first, filepath) + + else: + print("Needs to be a Part for export") + from PySide import QtGui + QtGui.QMessageBox.critical(None, + 'Need to select a Part for export', + 'Press OK') + + elif fileExt.lower == '.xml': + print('Export XML structure & solids') + exportGDML(first, filepath, '.xml') + + if fileExt == '.gemc': + exportGEMC(first, path, False) + + elif fileExt == '.GEMC': + exportGEMC(first, path, True) From 701fbb27f70a9d75dddfbb50b3acf7f4a74b4ebd Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Sat, 12 Feb 2022 09:34:43 +0000 Subject: [PATCH 02/45] Use Label for material Name --- freecad/gdml/GDMLMaterials.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/freecad/gdml/GDMLMaterials.py b/freecad/gdml/GDMLMaterials.py index 6d393e67e..fb4ec0cd8 100644 --- a/freecad/gdml/GDMLMaterials.py +++ b/freecad/gdml/GDMLMaterials.py @@ -106,13 +106,13 @@ def newGetGroupedMaterials(): refreshG4Materials(doc) docG4Materials = doc.G4Materials for g in docG4Materials.Group: - # print(f'g : {g.Name}') + # print(f'g : {g.Label}') for s in g.Group: - # print(f's : {s.Name}') + # print(f's : {s.Label}') if g.Name in GroupedMaterials: - GroupedMaterials[g.Name].append(s.Name) + GroupedMaterials[g.Label].append(s.Label) else: - GroupedMaterials[g.Name] = [s.Name] + GroupedMaterials[g.Label] = [s.Label] matList = [] docMaterials = doc.Materials if docMaterials is not None: From e1ce58730a3c72db6d0d8c4bd23f95093537a89a Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Sat, 12 Feb 2022 10:47:10 +0000 Subject: [PATCH 03/45] Fix no materials --- freecad/gdml/.gitignore | 1 + freecad/gdml/GDMLMaterials.py | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/freecad/gdml/.gitignore b/freecad/gdml/.gitignore index 6797c8f63..8ba2f1f76 100644 --- a/freecad/gdml/.gitignore +++ b/freecad/gdml/.gitignore @@ -1,4 +1,5 @@ *.pyc +\#*\# Resources/ColorDict.csv Resources/MapMaterials.xml diff --git a/freecad/gdml/GDMLMaterials.py b/freecad/gdml/GDMLMaterials.py index fb4ec0cd8..2d6cb88ed 100644 --- a/freecad/gdml/GDMLMaterials.py +++ b/freecad/gdml/GDMLMaterials.py @@ -50,7 +50,6 @@ def getMaterialsList(): doc = FreeCAD.activeDocument() try: materials = doc.Materials - geant4 = doc.Geant4 g4Mats = doc.getObject('G4Materials') except: @@ -60,7 +59,6 @@ def getMaterialsList(): print('Load Geant4 Materials XML') processGEANT4(doc, joinDir("Resources/Geant4Materials.xml")) materials = doc.Materials - geant4 = doc.Geant4 g4Mats = doc.getObject('G4Materials') try: @@ -82,6 +80,7 @@ def getMaterialsList(): return matList + def refreshG4Materials(doc): from .importGDML import joinDir, setupEtree, processMaterialsG4, newGroupPython, processNewG4 print('Get latest G4 Materials') @@ -97,10 +96,14 @@ def refreshG4Materials(doc): processNewG4(G4matGrp, mats_xml) doc.recompute() + def newGetGroupedMaterials(): + from .importGDML import joinDir, processGEANT4 print('New getGroupedMaterials') from .GDMLObjects import GroupedMaterials doc = FreeCAD.activeDocument() + if not hasattr(doc, 'Materials') or not hasattr(doc, 'G4Materials'): + processGEANT4(doc, joinDir("Resources/Geant4Materials.xml")) docG4Materials = doc.G4Materials if not hasattr(docG4Materials, 'version'): refreshG4Materials(doc) @@ -126,6 +129,7 @@ def newGetGroupedMaterials(): return GroupedMaterials + def getGroupedMaterials(): print('getGroupedMaterials') from .GDMLObjects import GroupedMaterials @@ -154,7 +158,8 @@ def getGroupedMaterials(): doc = FreeCAD.activeDocument() docMaterials = doc.Materials matList = [] - if docMaterials is not None: + + if doc.Materials is not None: for m in docMaterials.OutList: if m.Label != "Geant4": if m.Label not in matList: From 6ae8506218a0e61b84c384854426c02c0c1f6546 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Sat, 12 Feb 2022 19:05:44 +0000 Subject: [PATCH 04/45] Add creation of GDML object from extruded sketch - thanks to Munther Hindi --- freecad/gdml/GDMLShared.py | 2 +- freecad/gdml/init_gui.py | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/freecad/gdml/GDMLShared.py b/freecad/gdml/GDMLShared.py index b6ddcab27..23f3d7417 100644 --- a/freecad/gdml/GDMLShared.py +++ b/freecad/gdml/GDMLShared.py @@ -159,7 +159,7 @@ def processVariables(doc): except: globals()[name] = value # print('Value String : '+value) - variableObj = variablesGrp.newObject("App::DocumentObjectGroupPython", + variableObj = variablesGrp.newObject("App::DocumentObjectGroupPython", name) GDMLvariable(variableObj, name, value) # print("Globals") diff --git a/freecad/gdml/init_gui.py b/freecad/gdml/init_gui.py index 28d98c7ac..4e5d0ef32 100644 --- a/freecad/gdml/init_gui.py +++ b/freecad/gdml/init_gui.py @@ -34,6 +34,7 @@ #from FreeCAD import * import FreeCAD import PartGui +import SketcherGui import MeshGui import FreeCADGui from freecad.gdml import GDMLCommands, GDMLResources @@ -82,22 +83,25 @@ def QT_TRANSLATE_NOOP(scope, text): 'TorusCommand','TrapCommand','TubeCommand', \ 'BooleanCutCommand','BooleanIntersectionCommand', \ 'BooleanUnionCommand', \ - 'AddCompound','TessellateCommand','TessellateGmshCommand', \ + 'TessellateCommand','TessellateGmshCommand', \ 'DecimateCommand', \ 'Mesh_FromPartShape','Mesh_Evaluation', \ - 'Mesh2TessCommand','Tess2MeshCommand', 'TetrahedronCommand'] + 'Mesh2TessCommand','Tess2MeshCommand', 'TetrahedronCommand', \ + 'AddCompound'] toolbarcommands=['CycleCommand','ColourMapCommand','ExpandCommand', 'ExpandMaxCommand', 'SetMaterialCommand', \ - 'BoxCommand','ConeCommand', \ + 'Separator','Std_Part','BoxCommand','ConeCommand', \ 'ElTubeCommand', 'EllipsoidCommand','SphereCommand', \ - 'TorusCommand','TrapCommand','TubeCommand', - 'BooleanCutCommand','BooleanIntersectionCommand', \ - 'BooleanUnionCommand', \ - 'AddCompound','TessellateCommand','TessellateGmshCommand', \ + 'TorusCommand','TrapCommand','TubeCommand', \ + 'Sketcher_NewSketch','Part_Extrude', \ + 'Separator', 'BooleanCutCommand','BooleanIntersectionCommand', \ + 'BooleanUnionCommand','Separator', \ + 'TessellateCommand','TessellateGmshCommand', \ 'DecimateCommand', \ 'Mesh_FromPartShape','Mesh_Evaluation', \ - 'Mesh2TessCommand','Tess2MeshCommand','TetrahedronCommand'] + 'Mesh2TessCommand','Tess2MeshCommand','TetrahedronCommand', \ + 'AddCompound'] #parttoolbarcommands = ['Part_Cut','Part_Fuse','Part_Common'] #meshtoolbarcommands = ['Mesh_FromPartShape','Mesh_Evaluation'] From 99296289387fd7f79e6d79586b1b3248f303eebf Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Sat, 12 Feb 2022 20:02:07 +0000 Subject: [PATCH 05/45] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c151e86e9..0b4e71175 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,7 @@ will create * To read more about the general usage of the GDML workbench checkout the [GDML Workbench wiki](https://github.com/KeithSloan/GDML/wiki) * Converting STEP files to GDML [Convert Step to GDML](https://github.com/KeithSloan/GDML/wiki/Step2Tessellate) * Creating Tessellated Objects from FreeCAD Part Design Objects [Tessellate Part Design](https://github.com/KeithSloan/GDML/wiki/Tessellating-Part-Design-Objects) +* Creating a GDML object from an [Extruded sketch](https://github.com/KeithSloan/GDML/wiki/GDML-Object-from-FreeCAD-sketches)
From 6f7e90cb8a01c63f6156126b339a92e366b7513e Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Thu, 17 Feb 2022 07:18:03 +0000 Subject: [PATCH 06/45] Fix materials add Extrude as an icon --- freecad/gdml/GDMLCommands.py | 2 ++ freecad/gdml/GDMLMaterials.py | 49 ++++++++++++++++++----------------- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/freecad/gdml/GDMLCommands.py b/freecad/gdml/GDMLCommands.py index bfaa16aab..581a1a28e 100644 --- a/freecad/gdml/GDMLCommands.py +++ b/freecad/gdml/GDMLCommands.py @@ -196,7 +196,9 @@ def initUI(self): self.materialComboBox.addItems(self.groupedMaterials[groups[0]]) self.matList = [] for group in self.groupedMaterials: + print(group) self.matList += self.groupedMaterials[group] + print(len(self.matList)) self.completer = QtGui.QCompleter(self.matList, self) self.completer.setCaseSensitivity(QtCore.Qt.CaseInsensitive) self.materialComboBox.setCompleter(self.completer) diff --git a/freecad/gdml/GDMLMaterials.py b/freecad/gdml/GDMLMaterials.py index 2d6cb88ed..8c527e2b8 100644 --- a/freecad/gdml/GDMLMaterials.py +++ b/freecad/gdml/GDMLMaterials.py @@ -101,31 +101,32 @@ def newGetGroupedMaterials(): from .importGDML import joinDir, processGEANT4 print('New getGroupedMaterials') from .GDMLObjects import GroupedMaterials - doc = FreeCAD.activeDocument() - if not hasattr(doc, 'Materials') or not hasattr(doc, 'G4Materials'): - processGEANT4(doc, joinDir("Resources/Geant4Materials.xml")) - docG4Materials = doc.G4Materials - if not hasattr(docG4Materials, 'version'): - refreshG4Materials(doc) - docG4Materials = doc.G4Materials - for g in docG4Materials.Group: - # print(f'g : {g.Label}') - for s in g.Group: - # print(f's : {s.Label}') - if g.Name in GroupedMaterials: - GroupedMaterials[g.Label].append(s.Label) - else: - GroupedMaterials[g.Label] = [s.Label] - matList = [] - docMaterials = doc.Materials - if docMaterials is not None: - for m in docMaterials.OutList: - if m.Label != "Geant4": - if m.Label not in matList: - matList.append(m.Label) + if len(GroupedMaterials) == 0: + doc = FreeCAD.activeDocument() + if not hasattr(doc, 'Materials') or not hasattr(doc, 'G4Materials'): + processGEANT4(doc, joinDir("Resources/Geant4Materials.xml")) + docG4Materials = doc.G4Materials + if not hasattr(docG4Materials, 'version'): + refreshG4Materials(doc) + docG4Materials = doc.G4Materials + for g in docG4Materials.Group: + # print(f'g : {g.Label}') + for s in g.Group: + # print(f's : {s.Label}') + if g.Name in GroupedMaterials: + GroupedMaterials[g.Label].append(s.Label) + else: + GroupedMaterials[g.Label] = [s.Label] + matList = [] + docMaterials = doc.Materials + if docMaterials is not None: + for m in docMaterials.OutList: + if m.Label != "Geant4": + if m.Label not in matList: + matList.append(m.Label) - if len(matList) > 0: - GroupedMaterials['Normal'] = matList + if len(matList) > 0: + GroupedMaterials['Normal'] = matList return GroupedMaterials From df3a68df13963ad3ae0377af6921118f10261c5a Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Thu, 17 Feb 2022 20:28:28 +0000 Subject: [PATCH 07/45] Add sketch and extrude to commands --- freecad/gdml/init_gui.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freecad/gdml/init_gui.py b/freecad/gdml/init_gui.py index 4e5d0ef32..f73ef1c82 100644 --- a/freecad/gdml/init_gui.py +++ b/freecad/gdml/init_gui.py @@ -81,6 +81,7 @@ def QT_TRANSLATE_NOOP(scope, text): 'BoxCommand','ConeCommand','ElTubeCommand', \ 'EllipsoidCommand','SphereCommand', \ 'TorusCommand','TrapCommand','TubeCommand', \ + 'Sketcher_NewSketch','Part_Extrude', \ 'BooleanCutCommand','BooleanIntersectionCommand', \ 'BooleanUnionCommand', \ 'TessellateCommand','TessellateGmshCommand', \ From cafafa38f1950e7258c315de22d8d526967c8af2 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 1 Mar 2022 12:06:25 +0000 Subject: [PATCH 08/45] Stack --- freecad/gdml/GDMLObjects.py | 15 +++++++-- freecad/gdml/importGDML.py | 62 ++++++++++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/freecad/gdml/GDMLObjects.py b/freecad/gdml/GDMLObjects.py index 95cdfe294..af7d3f35f 100644 --- a/freecad/gdml/GDMLObjects.py +++ b/freecad/gdml/GDMLObjects.py @@ -562,7 +562,7 @@ def onChanged(self, fp, prop): if self.colour is None: fp.ViewObject.ShapeColor = colourMaterial(fp.material) - if prop in ['x', 'y', 'z', 'lunit']: + if prop in ['x', 'y', 'z', 'lunit', 'scale']: self.createGeometry(fp) # execute(self, fp): in GDMLsolid @@ -583,6 +583,11 @@ def createGeometry(self, fp): box = Part.makeBox(x, y, z) base = FreeCAD.Vector(-x/2, -y/2, -z/2) fp.Shape = translate(box, base) + if hasattr(fp,'scale'): + print('Rescale') + mat = FreeCAD.Matrix() + mat.scale(fp.scale) + fp.Shape = fp.Shape.transformGeometry(mat) fp.Placement = currPlacement def OnDocumentRestored(self, obj): @@ -733,7 +738,7 @@ def onChanged(self, fp, prop): if self.colour is None: fp.ViewObject.ShapeColor = colourMaterial(fp.material) - if prop in ['dx', 'dy', 'zmax', 'zcut', 'lunit']: + if prop in ['dx', 'dy', 'zmax', 'zcut', 'lunit', 'scale']: self.createGeometry(fp) # def execute(self, fp): in GDMLsolid @@ -784,6 +789,12 @@ def createGeometry(self, fp): fp.Shape = cone2.cut(box) else: fp.Shape = cone2 + if hasattr(fp,'scale'): + print('Update Scale') + mat = FreeCAD.Matrix() + mat.scale(fp.scale) + fp.Shape = fp.Shape.transformGeometry(mat) + fp.Placement = currPlacement diff --git a/freecad/gdml/importGDML.py b/freecad/gdml/importGDML.py index c61a26368..305db0993 100644 --- a/freecad/gdml/importGDML.py +++ b/freecad/gdml/importGDML.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # emacs insert date command: Ctrl-U ESC-! date -# Sat Jan 29 09:50:15 AM PST 2022 +# Mon Feb 28 12:47:38 PM PST 2022 # ************************************************************************** # * * # * Copyright (c) 2017 Keith Sloan * @@ -34,6 +34,7 @@ import os, io, sys, re import Part, Draft + def joinDir(path): import os __dirname__ = os.path.dirname(__file__) @@ -47,7 +48,7 @@ def joinDir(path): ########################## # global setup, define, mats_xml, solids, structure, extension -# globals constDict, filesDict +# globals constDict, filesDict if FreeCAD.GuiUp: import PartGui, FreeCADGui @@ -532,6 +533,7 @@ def createParaboloid(part, solid, material, colour, px, py, pz, rot, displayMode setDisplayMode(myparaboloid, displayMode) return myparaboloid + def createPolycone(part, solid, material, colour, px, py, pz, rot, displayMode): from .GDMLObjects import GDMLPolycone, GDMLzplane, \ ViewProvider, ViewProviderExtension @@ -612,6 +614,28 @@ def createPolyhedra(part, solid, material, colour, px, py, pz, rot, displayMode) return mypolyhedra +def createScaledSolid(part, solid, material, colour, px, py, pz, rot, displayMode): + print('ScaledSolid') + global solids + solidref = GDMLShared.getRef(solid, 'solidref') + newSolid = solids.find("*[@name='%s']" % solidref) + scaledObj = createSolid(part, newSolid, material, colour, + px, py, pz, rot, displayMode) + scale = solid.find('scale') + scaleName = scale.get('name') + sx = GDMLShared.getVal(scale, 'x') + sy = GDMLShared.getVal(scale, 'y') + sz = GDMLShared.getVal(scale, 'z') + scaleVec = FreeCAD.Vector(sx, sy, sz) + mat = FreeCAD.Matrix() + mat.scale(scaleVec) + scaledObj.recompute() + scaledObj.Shape.transformGeometry(mat) + scaledObj.recompute() + scaledObj.addProperty("App::PropertyVector", "scale","Base","scale"). \ + scale=scaleVec + return scaledObj + def createSphere(part, solid, material, colour, px, py, pz, rot, displayMode): from .GDMLObjects import GDMLSphere, ViewProvider # GDMLShared.setTrace(True) @@ -706,7 +730,7 @@ def createTrap(part, solid, material, colour, px, py, pz, rot, displayMode): aunit = getText(solid, 'aunit', 'rad') lunit = getText(solid, 'lunit', "mm") # print z - mytrap = newPartFeature(part, "GDMLTrap:"+getName(solid)) + mytrap = newPartFeature(part, "GDMLTrap_"+getName(solid)) GDMLTrap(mytrap, z, theta, phi, x1, x2, x3, x4, y1, y2, alpha1, aunit, lunit, material, colour) GDMLShared.trace("Position : "+str(px)+','+str(py)+','+str(pz)) @@ -808,6 +832,7 @@ def createTwistedtrap(part, solid, material, colour, px, py, pz, rot, displayMod setDisplayMode(mytrap, displayMode) return mytrap + def createTwistedtrd(part, solid, material, colour, px, py, pz, rot, displayMode): from .GDMLObjects import GDMLTwistedtrd, ViewProvider GDMLShared.trace("CreateTwistedtrd : ") @@ -859,6 +884,7 @@ def createTwistedtubs(part, solid, material, colour, px, py, pz, rot, displayMod setDisplayMode(mypart, displayMode) return mypart + def createXtru(part, solid, material, colour, px, py, pz, rot, displayMode): from .GDMLObjects import GDMLXtru, GDML2dVertex, GDMLSection, \ ViewProvider, ViewProviderExtension @@ -976,6 +1002,7 @@ def createCutTube(part, solid, material, colour, px, py, pz, rot, displayMode): setDisplayMode(mycuttube, displayMode) return mycuttube + def indexVertex(list, name): try: i = list.index(name) @@ -983,6 +1010,7 @@ def indexVertex(list, name): return -1 return i + def createTessellated(part, solid, material, colour, px, py, pz, rot, displayMode): from .GDMLObjects import GDMLTessellated, GDMLTriangular, \ @@ -1025,7 +1053,6 @@ def createTessellated(part, solid, material, colour, px, py, pz, rot, v3pos = len(vertNames) - 1 vertex.append(v3) # print(v3pos) - vType = elem.get('type') if elem.tag == 'triangular': faces.append([v1pos, v2pos, v3pos]) if elem.tag == 'quadrangular': @@ -1056,6 +1083,7 @@ def createTessellated(part, solid, material, colour, px, py, pz, rot, setDisplayMode(myTess, displayMode) return myTess + def parseMultiUnion(part, solid, material, colour, px, py, pz, rot, displayMode): global solids @@ -1202,6 +1230,10 @@ def createSolid(part, solid, material, colour, px, py, pz, rot, displayMode): return(createGenericPolyhedra(part, solid, material, colour, px, py, pz, rot, displayMode)) + if case('scaledSolid'): + return(createScaledSolid(part, solid, material, colour, \ + px, py, pz, rot, displayMode)) + if case('sphere'): return(createSphere(part, solid, material, colour, px, py, pz, rot, displayMode)) @@ -1372,6 +1404,7 @@ def parseVolume(parent, name, phylvl, displayMode): GDMLShared.trace("ParseVolume : "+name) expandVolume(parent, name, phylvl, displayMode) + def processVol(vol, parent, phylvl, displayMode): # GDMLShared.setTrace(True) from .GDMLObjects import checkMaterial @@ -1473,7 +1506,7 @@ def processVol(vol, parent, phylvl, displayMode): # If negative always parse otherwise increase level parsePhysVol(True, parent, pv, phylvl, displayMode) - else: # Just Add to structure + else: # Just Add to structure volRef = GDMLShared.getRef(pv, "volumeref") print('volRef : '+str(volRef)) nx, ny, nz = GDMLShared.getPosition(pv) @@ -1529,7 +1562,8 @@ def getItem(element, attribute): # returns None if not found return element.get(attribute) -def processIsotopes(isotopesGrp,mats_xml): + +def processIsotopes(isotopesGrp, mats_xml): from .GDMLObjects import GDMLisotope, ViewProvider for isotope in mats_xml.findall('isotope'): N = int(isotope.get('N')) @@ -1553,7 +1587,7 @@ def processIsotopes(isotopesGrp,mats_xml): 'Value').value = value -def processElements(elementsGrp,mats_xml): +def processElements(elementsGrp, mats_xml): from .GDMLObjects import GDMLelement, GDMLfraction, GDMLcomposite for element in mats_xml.findall('element'): name = element.get('name') @@ -1628,7 +1662,7 @@ def processMaterials(materialGrp, mats_xml, subGrp=None): # print(matType) # print(materialGrp.Group) mGrp = materialGrp.Group[subGrp.index(matType)] - + materialObj = newGroupPython(mGrp, name) GDMLmaterial(materialObj, name) formula = material.get('formula') @@ -1673,7 +1707,6 @@ def processMaterials(materialGrp, mats_xml, subGrp=None): materialObj.addProperty("App::PropertyString", 'Tunit', 'GDMLmaterial', "T ZZZUnit").Tunit = Tunit - Tvalue = GDMLShared.getVal(T, 'value') MEE = material.find('MEE') if MEE is not None: Munit = MEE.get('unit') @@ -1796,6 +1829,7 @@ def processGEANT4(doc, filename): geant4Grp = newGroupPython(materials, "Geant4") processMaterialsG4(geant4Grp, root) + def processMaterialsDocSet(doc, root): print('Process Materials') mats_xml = root.find('materials') @@ -1819,7 +1853,7 @@ def processMaterialsDocSet(doc, root): "Materials") processMaterials(materialsGrp, mats_xml) - + def processNewG4(materialsGrp, mats_xml): print('process new G4') matTypes = ['NIST', 'Element', 'HEP', 'Space', 'BioChemical'] @@ -1827,7 +1861,7 @@ def processNewG4(materialsGrp, mats_xml): newGroupPython(materialsGrp, t) processMaterials(materialsGrp, mats_xml, matTypes) - + def processMaterialsG4(G4rp, root): mats_xml = root.find('materials') if mats_xml is not None: @@ -1836,11 +1870,11 @@ def processMaterialsG4(G4rp, root): elementsGrp = newGroupPython(G4rp, "G4Elements") processElements(elementsGrp, mats_xml) materialsGrp = newGroupPython(G4rp, "G4Materials") - materialsGrp.addProperty('App::PropertyFloat','version','Base'). \ - version = 1.0 + materialsGrp.addProperty('App::PropertyFloat', 'version', 'Base'). \ + version = 1.0 processNewG4(materialsGrp, mats_xml) - + def processDefines(root, doc): GDMLShared.trace("Call set Define") GDMLShared.setDefine(root.find('define')) From 1746c0b41101032935013a3910d4b95966f208da Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 1 Mar 2022 19:28:42 +0000 Subject: [PATCH 09/45] Fix Rotation on import --- freecad/gdml/GDMLShared.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freecad/gdml/GDMLShared.py b/freecad/gdml/GDMLShared.py index 23f3d7417..7846d8138 100644 --- a/freecad/gdml/GDMLShared.py +++ b/freecad/gdml/GDMLShared.py @@ -369,7 +369,8 @@ def processPlacement(base, rot): rotY = FreeCAD.Rotation(FreeCAD.Vector(0, 1, 0), -y) rotZ = FreeCAD.Rotation(FreeCAD.Vector(0, 0, 1), -z) - rot = rotZ*rotY*rotX + rot = rotX*rotY*rotZ + #rot = rotZ*rotY*rotX # rot = rotX.multiply(rotY).multiply(rotZ) # rot = rotX # c_rot = FreeCAD.Vector(0,0,0) # Center of rotation From 59da9f0913a9d18c11fab760a6df37de6dcd3e48 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 1 Mar 2022 20:12:00 +0000 Subject: [PATCH 10/45] Add scaled support to all GDMLObjects --- freecad/gdml/GDMLObjects.py | 127 +++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 2 deletions(-) diff --git a/freecad/gdml/GDMLObjects.py b/freecad/gdml/GDMLObjects.py index af7d3f35f..e885ef5e3 100644 --- a/freecad/gdml/GDMLObjects.py +++ b/freecad/gdml/GDMLObjects.py @@ -363,6 +363,12 @@ def __init__(self, obj): def getMaterial(self): return obj.material + def scale(self,fp): + print('Rescale') + mat = FreeCAD.Matrix() + mat.scale(fp.scale) + fp.Shape = fp.Shape.transformGeometry(mat) + def execute(self, fp): self.createGeometry(fp) @@ -476,6 +482,10 @@ def onChanged(self, fp, prop): 'dz', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid # http://geant4-userdoc.web.cern.ch/geant4-userdoc/UsersGuides/ForApplicationDeveloper/html/Detector/Geometry/geomSolids.html @@ -562,9 +572,13 @@ def onChanged(self, fp, prop): if self.colour is None: fp.ViewObject.ShapeColor = colourMaterial(fp.material) - if prop in ['x', 'y', 'z', 'lunit', 'scale']: + if prop in ['x', 'y', 'z', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -649,6 +663,10 @@ def onChanged(self, fp, prop): 'aunit', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -738,9 +756,13 @@ def onChanged(self, fp, prop): if self.colour is None: fp.ViewObject.ShapeColor = colourMaterial(fp.material) - if prop in ['dx', 'dy', 'zmax', 'zcut', 'lunit', 'scale']: + if prop in ['dx', 'dy', 'zmax', 'zcut', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -841,6 +863,10 @@ def onChanged(self, fp, prop): if prop in ['ax', 'by', 'cz', 'zcut1', 'zcut2', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -932,6 +958,11 @@ def onChanged(self, fp, prop): if prop in ['dx', 'dy', 'dz', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -986,6 +1017,10 @@ def onChanged(self, fp, prop): # print(dir(fp)) self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -1046,6 +1081,10 @@ def onChanged(self, fp, prop): if prop in ['x', 'y', 'z', 'alpha', 'theta', 'phi', 'aunit', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid @@ -1166,6 +1205,10 @@ def onChanged(self, fp, prop): if prop in ['rmin', 'rmax', 'z', 'inst', 'outst', 'aunit', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -1278,6 +1321,10 @@ def onChanged(self, fp, prop): if prop in ['rlo', 'rhi', 'z', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -1362,6 +1409,10 @@ def onChanged(self, fp, prop): if prop in ['startphi', 'deltaphi', 'numsides', 'aunit', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -1477,6 +1528,10 @@ def onChanged(self, fp, prop): if prop in ['startphi', 'deltaphi', 'numsides', 'aunit', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -1588,6 +1643,10 @@ def onChanged(self, fp, prop): # print(f'Change Prop : {prop}') self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -1675,6 +1734,10 @@ def onChanged(self, fp, prop): if prop in ['x', 'y', 'z', 'PhiTwist', 'lunit', 'aunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -1775,6 +1838,10 @@ def onChanged(self, fp, prop): 'aunit', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -1894,6 +1961,10 @@ def onChanged(self, fp, prop): if prop in ['x1', 'y1', 'x2', 'y2', 'z', 'PhiTwist', 'lunit', 'aunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -1998,6 +2069,10 @@ def onChanged(self, fp, prop): 'phi', 'lunit', 'aunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -2089,6 +2164,10 @@ def onChanged(self, fp, prop): if prop in ['startphi', 'deltaphi', 'aunit', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def layerPoints(self, polyList, sf, xOffset, yOffset, zPosition): @@ -2339,6 +2418,10 @@ def onChanged(self, fp, prop): if prop in ['startphi', 'deltaphi', 'aunit', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -2441,6 +2524,10 @@ def onChanged(self, fp, prop): if prop in ['startphi', 'deltaphi', 'aunit', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -2521,6 +2608,10 @@ def onChanged(self, fp, prop): 'deltatheta', 'aunit', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -2662,6 +2753,10 @@ def onChanged(self, fp, prop): 'aunit', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self,fp): @@ -2779,6 +2874,10 @@ def onChanged(self, fp, prop): if prop in ['z', 'x1', 'x2', 'y1', 'y2', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -2864,6 +2963,10 @@ def onChanged(self, fp, prop): 'aunit', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -2957,6 +3060,10 @@ def onChanged(self, fp, prop): 'highX', 'highY', 'highZ', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def cutShapeWithPlane(self, shape, plane, depth): @@ -3164,6 +3271,10 @@ def onChanged(self, fp, prop): self.reMesh(fp) self.execute(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + def execute(self, fp): # Here for remesh? self.createGeometry(fp) @@ -3278,6 +3389,10 @@ def onChanged(self, fp, prop): if fp.editable is True: self.addProperties() + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + def addProperties(self): print('Add Properties') @@ -3375,6 +3490,10 @@ def onChanged(self, fp, prop): if prop in ['v1', 'v2', 'v3', 'v4', 'lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def createGeometry(self, fp): @@ -3434,6 +3553,10 @@ def onChanged(self, fp, prop): if prop in ['lunit']: self.createGeometry(fp) + if prop in ['scale']: + self.createGeometry(fp) + super().scale(fp) + # def execute(self, fp): in GDMLsolid def makeTetra(self, pt1, pt2, pt3, pt4): From 0a3fd2ac07778e91ae138e4077fcc699ad54503d Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Wed, 2 Mar 2022 18:03:37 +0000 Subject: [PATCH 11/45] Fix Tessellate Placements and Build Materials list --- freecad/gdml/GDMLCommands.py | 15 +++++++++------ freecad/gdml/GDMLObjects.py | 16 ++++++++++++---- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/freecad/gdml/GDMLCommands.py b/freecad/gdml/GDMLCommands.py index 581a1a28e..4fd1d92e8 100644 --- a/freecad/gdml/GDMLCommands.py +++ b/freecad/gdml/GDMLCommands.py @@ -1236,12 +1236,15 @@ def Activated(self): # GDMLTessellated(myTess,mesh.Topology[0],mesh.Topology[1], \ GDMLTessellated(myTess, mesh.Topology[0], mesh.Facets, True, "mm", mat) - # Update Part Placment with source Placement - vol.Placement = obj.Placement - base = obj.Placement.Base - print(type(base)) - myTess.Placement.Base = base.multiply(-1.0) - FreeCAD.ActiveDocument.recompute() + # After meshing points have values as per identity Placement + myTess.Placement = FreeCAD.Placement() + # Update Part Placement with source Placement + #vol.Placement = obj.Placement + #mat = obj.Placement.toMatrix().inverse() + #myTess.Placement = FreeCAD.Placement() + #myTess.recompute() + #myTess.Shape.transformGeometry(mat) + myTess.recompute() if FreeCAD.GuiUp: ViewProvider(myTess.ViewObject) obj.ViewObject.Visibility = False diff --git a/freecad/gdml/GDMLObjects.py b/freecad/gdml/GDMLObjects.py index 95cdfe294..d58fb7354 100644 --- a/freecad/gdml/GDMLObjects.py +++ b/freecad/gdml/GDMLObjects.py @@ -64,7 +64,8 @@ def addMaterialsFromGroup(doc, MatList, grpName): if mmats is not None: if hasattr(mmats, 'Group'): for i in mmats.Group: - MatList.append(i.Name) + if i.Label != 'Geant4': + MatList.append(i.Label) def rebuildMaterialsList(): @@ -72,7 +73,12 @@ def rebuildMaterialsList(): print('Restore MaterialsList from Materials Lists') doc = FreeCAD.ActiveDocument addMaterialsFromGroup(doc, MaterialsList, "Materials") - addMaterialsFromGroup(doc, MaterialsList, "G4Materials") + #print(MaterialsList) + G4Materials = doc.getObject('G4Materials') + if G4Materials is not None : + for g in G4Materials.Group: + #print(g.Label) + addMaterialsFromGroup(doc, MaterialsList, g.Label) # print('MaterialsList') # print(MaterialsList) @@ -87,9 +93,11 @@ def checkMaterial(material): def setMaterial(obj, m): - # print('setMaterial') + print('setMaterial') if MaterialsList is not None: if len(MaterialsList) > 0: + print('MaterialsList Ok') + #print(MaterialsList) obj.material = MaterialsList obj.material = 0 if not (m == 0 or m is None): @@ -358,7 +366,7 @@ def __init__(self, obj): if (ln - r) >= 2: # print('Tool : '+obj.Label) return # Let Placement default to 0 - obj.setEditorMode('Placement', 2) + #obj.setEditorMode('Placement', 2) def getMaterial(self): return obj.material From 62d768b62dabcbf80c52e411903c2093fdbee22a Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Thu, 3 Mar 2022 14:48:41 +0000 Subject: [PATCH 12/45] Gmsh --- freecad/gdml/GDMLObjects.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freecad/gdml/GDMLObjects.py b/freecad/gdml/GDMLObjects.py index d58fb7354..9b9d265c0 100644 --- a/freecad/gdml/GDMLObjects.py +++ b/freecad/gdml/GDMLObjects.py @@ -3134,7 +3134,8 @@ def __init__(self, obj, sourceObj, meshLen, vertex, facets, lunit, self.colour = colour obj.Proxy = self - def updateParams(self, vertex, facets): + def updateParams(self, vertex, facets, flag): + self.Vertex = vertex self.Facets = facets self.facets = len(facets) From 0477a4d52a811b445d8d07a03cf891c5c3ccdac9 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Thu, 3 Mar 2022 15:22:53 +0000 Subject: [PATCH 13/45] Fix tess Quad --- freecad/gdml/exportGDML.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freecad/gdml/exportGDML.py b/freecad/gdml/exportGDML.py index ddc488960..437f59bf8 100644 --- a/freecad/gdml/exportGDML.py +++ b/freecad/gdml/exportGDML.py @@ -1085,10 +1085,10 @@ def processGDMLTessellatedObject(obj): for f in obj.Shape.Faces: # print(f'Normal at : {n} dot {dot} {clockWise}') vertexes = f.OuterWire.OrderedVertexes + i0 = vertexHashcodeDict[vertexes[0].hashCode()] + i1 = vertexHashcodeDict[vertexes[1].hashCode()] + i2 = vertexHashcodeDict[vertexes[2].hashCode()] if len(f.Edges) == 3: - i0 = vertexHashcodeDict[vertexes[0].hashCode()] - i1 = vertexHashcodeDict[vertexes[1].hashCode()] - i2 = vertexHashcodeDict[vertexes[2].hashCode()] ET.SubElement(tess, 'triangular', { 'vertex1': tessVname+str(i0), 'vertex2': tessVname+str(i1), From 0ee6c4c39801b97e824833b1757704105e3001dc Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Sat, 5 Mar 2022 07:50:37 +0000 Subject: [PATCH 14/45] stack --- freecad/gdml/GDMLObjects.py | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/freecad/gdml/GDMLObjects.py b/freecad/gdml/GDMLObjects.py index e885ef5e3..4e0c66d82 100644 --- a/freecad/gdml/GDMLObjects.py +++ b/freecad/gdml/GDMLObjects.py @@ -364,7 +364,7 @@ def getMaterial(self): return obj.material def scale(self,fp): - print('Rescale') + print(f'Rescale : {fp.scale}') mat = FreeCAD.Matrix() mat.scale(fp.scale) fp.Shape = fp.Shape.transformGeometry(mat) @@ -561,7 +561,7 @@ def __init__(self, obj, x, y, z, lunit, material, colour=None): def onChanged(self, fp, prop): '''Do something when a property has changed''' - # print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) + print(fp.Label+" State : "+str(fp.State)+" prop : "+prop) # Changing Shape in createGeometry will redrive onChanged if ('Restore' in fp.State): return @@ -577,13 +577,12 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # execute(self, fp): in GDMLsolid def createGeometry(self, fp): - # print('createGeometry') - # print(fp) + print('createGeometry') + print(fp) if all((fp.x, fp.y, fp.z)): currPlacement = fp.Placement @@ -597,12 +596,9 @@ def createGeometry(self, fp): box = Part.makeBox(x, y, z) base = FreeCAD.Vector(-x/2, -y/2, -z/2) fp.Shape = translate(box, base) - if hasattr(fp,'scale'): - print('Rescale') - mat = FreeCAD.Matrix() - mat.scale(fp.scale) - fp.Shape = fp.Shape.transformGeometry(mat) fp.Placement = currPlacement + if hasattr(fp,'scale'): + super().scale(fp) def OnDocumentRestored(self, obj): print('Doc Restored') @@ -811,12 +807,6 @@ def createGeometry(self, fp): fp.Shape = cone2.cut(box) else: fp.Shape = cone2 - if hasattr(fp,'scale'): - print('Update Scale') - mat = FreeCAD.Matrix() - mat.scale(fp.scale) - fp.Shape = fp.Shape.transformGeometry(mat) - fp.Placement = currPlacement From e7e37d6eef78b40eaaed2b96981f4b06b68523f5 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Sun, 6 Mar 2022 12:58:18 +0000 Subject: [PATCH 15/45] Scaled Solid Support --- freecad/gdml/GDMLObjects.py | 62 +++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 33 deletions(-) diff --git a/freecad/gdml/GDMLObjects.py b/freecad/gdml/GDMLObjects.py index 4e0c66d82..428bb54fb 100644 --- a/freecad/gdml/GDMLObjects.py +++ b/freecad/gdml/GDMLObjects.py @@ -535,6 +535,7 @@ def createGeometry(self, fp): faceYminA, faceYminB, faceYmaxA, faceYmaxB, faceZmin, faceZmax])) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -597,8 +598,7 @@ def createGeometry(self, fp): base = FreeCAD.Vector(-x/2, -y/2, -z/2) fp.Shape = translate(box, base) fp.Placement = currPlacement - if hasattr(fp,'scale'): - super().scale(fp) + if hasattr(fp,'scale'): super().scale(fp) def OnDocumentRestored(self, obj): print('Doc Restored') @@ -661,7 +661,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -712,6 +711,7 @@ def createGeometry(self, fp): fp.Shape = translate(cone, base) else: fp.Shape = translate(cone3, base) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -757,7 +757,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -807,6 +806,7 @@ def createGeometry(self, fp): fp.Shape = cone2.cut(box) else: fp.Shape = cone2 + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -855,7 +855,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -906,6 +905,7 @@ def createGeometry(self, fp): base = FreeCAD.Vector(0, 0, 0) fp.Shape = translate(shape, base) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -950,8 +950,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) - # def execute(self, fp): in GDMLsolid @@ -969,6 +967,7 @@ def createGeometry(self, fp): newtube = tube.transformGeometry(mat) base = FreeCAD.Vector(0, 0, -(fp.dz*mul)) # dz is half height fp.Shape = translate(newtube, base) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -1009,7 +1008,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -1020,6 +1018,7 @@ def createGeometry(self, fp): mul = GDMLShared.getMult(fp.lunit) r = mul * fp.r fp.Shape = Part.makeSphere(r) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -1073,8 +1072,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) - # def execute(self, fp): in GDMLsolid @@ -1143,6 +1140,7 @@ def createGeometry(self, fp): # center = (v7 - v1)/2 fp.Shape = translate(solid, -center) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -1197,7 +1195,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -1266,7 +1263,7 @@ def createGeometry(self, fp): rr = [math.sqrt(sqrtan1*zi*zi + rmin*rmin) for zi in zz] innersolid = rotateAroundZ(NUMBER_OF_DIVISIONS, zz, rr) fp.Shape = outersolid.cut(innersolid) - + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -1313,7 +1310,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -1350,7 +1346,7 @@ def createGeometry(self, fp): rr = [math.sqrt(k1*zi+k2) for zi in zz] outersolid = rotateAroundZ(NUMBER_OF_DIVISIONS, zz, rr) fp.Shape = outersolid - + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -1401,7 +1397,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -1470,6 +1465,7 @@ def createGeometry(self, fp): fp.Shape = newShape else: fp.Shape = shape + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -1520,7 +1516,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -1583,6 +1578,7 @@ def createGeometry(self, fp): shell = Part.makeShell(faces) solid = Part.makeSolid(shell) fp.Shape = solid + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -1635,7 +1631,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -1661,6 +1656,7 @@ def createGeometry(self, fp): if fp.startphi != 0: torus.rotate(spnt, sdir, getAngleDeg(fp.aunit, fp.startphi)) fp.Shape = torus + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -1726,7 +1722,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -1762,6 +1757,7 @@ def createGeometry(self, fp): loft = Part.makeLoft(slices, True, False) fp.Shape = loft + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement def OnDocumentRestored(self, obj): @@ -1830,7 +1826,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -1887,6 +1882,7 @@ def createGeometry(self, fp): loft = Part.makeLoft(slices, True, False) fp.Shape = loft + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -1953,7 +1949,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -1992,6 +1987,7 @@ def createGeometry(self, fp): loft = Part.makeLoft(slices, True, False) fp.Shape = loft + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement def OnDocumentRestored(self, obj): @@ -2061,7 +2057,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -2116,6 +2111,7 @@ def createGeometry(self, fp): loft = Part.makeLoft(slices, True, False) fp.Shape = loft + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement def OnDocumentRestored(self, obj): @@ -2156,7 +2152,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -2256,6 +2251,7 @@ def createGeometry(self, fp): # print(dir(fp)) # solid.exportBrep("/tmp/"+fp.Label+".brep") fp.Shape = solid + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -2410,7 +2406,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -2466,6 +2461,7 @@ def createGeometry(self, fp): angleDeltaPhiDeg) # compound of all faces fp.Shape = Part.makeCompound(listShape) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -2516,7 +2512,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -2543,6 +2538,7 @@ def createGeometry(self, fp): solid = Part.makeSolid(surf) fp.Shape = solid + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -2600,7 +2596,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -2684,6 +2679,7 @@ def createGeometry(self, fp): fp.Shape = sphere2 else: fp.Shape = sphere2.cut(Part.makeSphere(rmin)) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -2745,7 +2741,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -2819,6 +2814,7 @@ def createGeometry(self,fp): center = (topCenter+botCenter)/2 fp.Shape = translate(solid, -center) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -2866,7 +2862,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -2902,6 +2897,7 @@ def createGeometry(self, fp): # solid = Part.makePolygon([v1,v2,v3,v4,v5,v6,v7,v1]) fp.Shape = solid + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -2955,7 +2951,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -2982,6 +2977,7 @@ def createGeometry(self, fp): base = FreeCAD.Vector(0, 0, -z/2) fp.Shape = translate(tube, base) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -3052,7 +3048,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -3096,6 +3091,7 @@ def createGeometry(self, fp): cutTube2 = self.cutShapeWithPlane(cutTube1, botPlane, depth) base = FreeCAD.Vector(0, 0, -z/2) fp.Shape = translate(cutTube2, base) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement def createGeometry_hardcoded(self, fp): @@ -3263,7 +3259,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) def execute(self, fp): # Here for remesh? self.createGeometry(fp) @@ -3324,6 +3319,7 @@ def createGeometry(self, fp): # base = FreeCAD.Vector(0,0,0) # fp.Shape = translate(solid,base) fp.Shape = solid + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -3381,7 +3377,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) def addProperties(self): print('Add Properties') @@ -3396,6 +3391,7 @@ def createGeometry(self, fp): fp.pshape = self.pshape fp.vertex = self.vertex fp.facets = self.facets + if hasattr(fp,'scale'): super().scale(fp) def createShape(self, vertex, facets, flag): # Viewing outside of face vertex must be counter clockwise @@ -3482,7 +3478,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -3498,6 +3493,7 @@ def createGeometry(self, fp): face3 = Part.Face(Part.makePolygon([pt4, pt2, pt3, pt4])) face4 = Part.Face(Part.makePolygon([pt1, pt3, pt4, pt1])) fp.Shape = Part.makeSolid(Part.makeShell([face1, face2, face3, face4])) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement @@ -3545,7 +3541,6 @@ def onChanged(self, fp, prop): if prop in ['scale']: self.createGeometry(fp) - super().scale(fp) # def execute(self, fp): in GDMLsolid @@ -3569,6 +3564,7 @@ def createGeometry(self, fp): pt4 = mul * t[3] tetraShells.append(self.makeTetra(pt1, pt2, pt3, pt4)) fp.Shape = Part.makeCompound(tetraShells) + if hasattr(fp,'scale'): super().scale(fp) fp.Placement = currPlacement From 393c92b01c52bf54b93ad9d066614a357b0d4b1a Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Sun, 6 Mar 2022 15:39:35 +0000 Subject: [PATCH 16/45] Add package.xml --- freecad/gdml/package.xml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 freecad/gdml/package.xml diff --git a/freecad/gdml/package.xml b/freecad/gdml/package.xml new file mode 100644 index 000000000..c191d526b --- /dev/null +++ b/freecad/gdml/package.xml @@ -0,0 +1,26 @@ + + + GDML workbench + An external workbench for creating GDML models for Geant4 and Root> + 1.8 Beta + Keith Sloan + LGPL-2.1 + https://github.com/KeithSloan/GDML.git + https://github.com/KeithSloan/GDML.git + https://github.com/KeithSloan/GDML/wiki + + + + GDML workbench + GDMLWorkbench + A workbench for creating GDML models for Geant4 & ROOT. + 1.8 Beta + ./ + freecad/gdml/Resources/icons/GDMLWorkbench.svg + 0.19.3 + lxml + gmsh + + + + From af0835784bd7a57c4b5c337a4281502156e77514 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Sun, 6 Mar 2022 16:13:51 +0000 Subject: [PATCH 17/45] Add package --- metadata.txt | 2 ++ freecad/gdml/package.xml => package.xml | 12 ++++-------- 2 files changed, 6 insertions(+), 8 deletions(-) create mode 100644 metadata.txt rename freecad/gdml/package.xml => package.xml (67%) diff --git a/metadata.txt b/metadata.txt new file mode 100644 index 000000000..50559ffab --- /dev/null +++ b/metadata.txt @@ -0,0 +1,2 @@ +workbenches=Part,Mesh +pylibs=lxml,gmsh diff --git a/freecad/gdml/package.xml b/package.xml similarity index 67% rename from freecad/gdml/package.xml rename to package.xml index c191d526b..79e74542c 100644 --- a/freecad/gdml/package.xml +++ b/package.xml @@ -1,25 +1,21 @@ - + GDML workbench An external workbench for creating GDML models for Geant4 and Root> 1.8 Beta + 2022-03-06 Keith Sloan LGPL-2.1 - https://github.com/KeithSloan/GDML.git - https://github.com/KeithSloan/GDML.git + https://github.com/KeithSloan/GDML https://github.com/KeithSloan/GDML/wiki + https://github.com/KeithSloan/GDML/blob/master/README.md - GDML workbench GDMLWorkbench - A workbench for creating GDML models for Geant4 & ROOT. - 1.8 Beta ./ freecad/gdml/Resources/icons/GDMLWorkbench.svg 0.19.3 - lxml - gmsh From b7e20bf1349fe5e1f9e14ad56e9d38c69eb80efb Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Mon, 7 Mar 2022 12:50:34 +0000 Subject: [PATCH 18/45] Fix package definition --- package.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.xml b/package.xml index 79e74542c..d422d6504 100644 --- a/package.xml +++ b/package.xml @@ -1,7 +1,7 @@ GDML workbench - An external workbench for creating GDML models for Geant4 and Root> + An external workbench for creating GDML models for Geant4 and Root> 1.8 Beta 2022-03-06 Keith Sloan From 92586ec6681ac9a4ef79a509b0a6fc93e0062d25 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 8 Mar 2022 08:47:29 +0000 Subject: [PATCH 19/45] Update README.md Update README with details of new branch beta2 which has a number of exciting new enhancements and facilities. --- README.md | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 0b4e71175..09b0fafa2 100644 --- a/README.md +++ b/README.md @@ -32,38 +32,51 @@ the required libraries section of this README. #### Regression with STEP export -With OpenCasCade v7.5.0 and v7.5.1 as used in FreeCAD 0.19.2 +There is a regression with STEP export in OpenCasCade v7.5.0 and v7.5.1 as used in FreeCAD 0.19.2 +Recomended to use at least FreeCAD 0.19.3 with OpenCasCade v7.5.3 ( i.e OCC 7.5.3 ) -#### Problem with export of Rotations +#### NEW BRANCH beta2 -This issues applies to all operating systems. To fix a problem with export and rotations please use +A new branch beta2 has a lot of exciting enhancements. The plan is that in time this will merged with the master branch -* the FreeCAD_Assembly3 release STABLE or DAILY see https://github.com/realthunder/FreeCAD_assembly3/releases +* The branch is selectable using the new Addon manager in FreeCAD 0.20 - scroll down to Assets. + For FreeCAD 0.20 builds see weekly builds at https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds +* Supports GDML exports without needing toEuler facility in FreeCAD +* Creation of GDML solids from FreeCAD a sketch + * Extrude + * Revolve +* Creation of Arrays +* Creation of Mirrors +* Export of GDML object takes into account the Placements of the GDML objects and the App::Part ( GDML Volume ) -* the GDML git branch called **link3**. Install it via: - 1. Access your FreeCAD config directory (for example on Linux: `cd ~/.FreeCAD/Mod/GDML`) - 2. `git fetch origin link3` - 3. `git checkout link3` - 4. Restart FreeCAD +#### Enhancements with Realthunder LinkDaily branch) -You should also see a dramatic improvement especially with LinkDaily in import times with these builds. +For installation see the FreeCAD_Assembly3 release STABLE or DAILY see https://github.com/realthunder/FreeCAD_assembly3/releases +scroll down to Assets. -#### Enhanced Rendering (on Realthunder's LinkDaily branch) -There is also the option to use enhanced rendering which helps with complex models. To enable enhanced rendering in LinkDaily: +Realthunders LinkDaily branch has the following enhancements + +* Faster import of GDML objects +* Add extra toEulerAngles function ( Note: as of branch beta2 this is no longer neede ) +* Enhanced Rendering which helps with complex models. + +To enable enhanced rendering in LinkDaily: `FreeCAD > Preferences > Display > Render Cache > Experimental` If you like what you see you might like to thank Lei Zhang by contributing to his [FreeCAD Patreon](https://www.patreon.com/thundereal/posts) -You can use FreeCAD 0.19.1 but this does not have the toEulerAngles function that facilities the -fixing of exports with rotations and import speed will still be slow. The toEulerAngles facility should be in the -process of being added to FreeCAD 0.20 -For latest versions of FreeCAD 0.19 see the Assets section of https://github.com/FreeCAD/FreeCAD/releases +#### Problem with export of Rotations ( Fixed in beta2 ) + +For correct export of GDML rotations please use one the the following + +* beta2 branch ( All operating systems even FreeCAD 0.19) +* A Realthunder version of FreeCAD +* A recent version fo FreeCAD 0.20 -**Changes to Placement (GDML Position & Rotation)** +#### Changes to Placement (GDML Position & Rotation) [Fixed in beta2] In order to support copies of GDML Volumes the following changes have been made From 902f750908701526844fe6b81c20156c725531ed Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 8 Mar 2022 08:53:02 +0000 Subject: [PATCH 20/45] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 09b0fafa2..691a4098a 100644 --- a/README.md +++ b/README.md @@ -44,13 +44,13 @@ A new branch beta2 has a lot of exciting enhancements. The plan is that in time For FreeCAD 0.20 builds see weekly builds at https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds * Supports GDML exports without needing toEuler facility in FreeCAD * Creation of GDML solids from FreeCAD a sketch - * Extrude + * [Extruded sketch](https://github.com/KeithSloan/GDML/wiki/GDML-Object-from-FreeCAD-sketches) * Revolve * Creation of Arrays * Creation of Mirrors * Export of GDML object takes into account the Placements of the GDML objects and the App::Part ( GDML Volume ) -#### Enhancements with Realthunder LinkDaily branch) +#### Enhancements with Realthunder LinkDaily branch For installation see the FreeCAD_Assembly3 release STABLE or DAILY see https://github.com/realthunder/FreeCAD_assembly3/releases scroll down to Assets. From 7c7eef5b853388076b691effbd911ee3cfa63e98 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 8 Mar 2022 08:54:20 +0000 Subject: [PATCH 21/45] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 691a4098a..0bacd52cd 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ A new branch beta2 has a lot of exciting enhancements. The plan is that in time For FreeCAD 0.20 builds see weekly builds at https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds * Supports GDML exports without needing toEuler facility in FreeCAD -* Creation of GDML solids from FreeCAD a sketch +* Creation of GDML solids from a FreeCAD sketch * [Extruded sketch](https://github.com/KeithSloan/GDML/wiki/GDML-Object-from-FreeCAD-sketches) * Revolve * Creation of Arrays From 649548df89a8e5d1d9b475c3ca1f3eb71ca03a7b Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 8 Mar 2022 08:56:19 +0000 Subject: [PATCH 22/45] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0bacd52cd..df406352c 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ scroll down to Assets. Realthunders LinkDaily branch has the following enhancements * Faster import of GDML objects -* Add extra toEulerAngles function ( Note: as of branch beta2 this is no longer neede ) +* Add extra toEulerAngles function ( Note: as of branch beta2 this is no longer needed ) * Enhanced Rendering which helps with complex models. To enable enhanced rendering in LinkDaily: From 328cb202462039d680ad70bc395f080c95ddf539 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 8 Mar 2022 16:27:58 +0000 Subject: [PATCH 23/45] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index df406352c..914ba0b28 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,11 @@ A new branch beta2 has a lot of exciting enhancements. The plan is that in time For FreeCAD 0.20 builds see weekly builds at https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds * Supports GDML exports without needing toEuler facility in FreeCAD -* Creation of GDML solids from a FreeCAD sketch - * [Extruded sketch](https://github.com/KeithSloan/GDML/wiki/GDML-Object-from-FreeCAD-sketches) - * Revolve -* Creation of Arrays -* Creation of Mirrors +* Creation of GDML solids from a [FreeCAD sketches](https://github.com/KeithSloan/GDML/wiki/GDML-Object-from-FreeCAD-sketches) + * [Extrude](https://github.com/KeithSloan/GDML/wiki/Extrude--:-Examples-of-Extruded-sketches) + * [Revolve](https://github.com/KeithSloan/GDML/wiki/Revolved-:-Examples-of-Revolved-sketches) +* [Creation of Arrays](https://github.com/KeithSloan/GDML/wiki/Array-:-Example-of-use-of-Array) +* [Creation of Mirrors](https://github.com/KeithSloan/GDML/wiki/Mirror-:-Examples-of-use-of-Mirror) * Export of GDML object takes into account the Placements of the GDML objects and the App::Part ( GDML Volume ) #### Enhancements with Realthunder LinkDaily branch From 5dffa69ffcbc22bb3f85dd92053b9ca8087c0088 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 8 Mar 2022 16:30:35 +0000 Subject: [PATCH 24/45] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 914ba0b28..5108b53e8 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,11 @@ A new branch beta2 has a lot of exciting enhancements. The plan is that in time For FreeCAD 0.20 builds see weekly builds at https://github.com/FreeCAD/FreeCAD-Bundle/releases/tag/weekly-builds * Supports GDML exports without needing toEuler facility in FreeCAD -* Creation of GDML solids from a [FreeCAD sketches](https://github.com/KeithSloan/GDML/wiki/GDML-Object-from-FreeCAD-sketches) +* Creation of GDML solids from [FreeCAD Sketches](https://github.com/KeithSloan/GDML/wiki/GDML-Object-from-FreeCAD-sketches) * [Extrude](https://github.com/KeithSloan/GDML/wiki/Extrude--:-Examples-of-Extruded-sketches) * [Revolve](https://github.com/KeithSloan/GDML/wiki/Revolved-:-Examples-of-Revolved-sketches) -* [Creation of Arrays](https://github.com/KeithSloan/GDML/wiki/Array-:-Example-of-use-of-Array) -* [Creation of Mirrors](https://github.com/KeithSloan/GDML/wiki/Mirror-:-Examples-of-use-of-Mirror) +* Creation of [Arrays](https://github.com/KeithSloan/GDML/wiki/Array-:-Example-of-use-of-Array) +* Creation of [Mirrors](https://github.com/KeithSloan/GDML/wiki/Mirror-:-Examples-of-use-of-Mirror) * Export of GDML object takes into account the Placements of the GDML objects and the App::Part ( GDML Volume ) #### Enhancements with Realthunder LinkDaily branch From 3ff62e8ee4b9861d9676f18f59927c240b3dc15a Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Mon, 14 Mar 2022 20:14:03 +0000 Subject: [PATCH 25/45] Fix GDMLObjects getMaterial --- freecad/gdml/GDMLObjects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freecad/gdml/GDMLObjects.py b/freecad/gdml/GDMLObjects.py index abcd147cc..c2228f381 100644 --- a/freecad/gdml/GDMLObjects.py +++ b/freecad/gdml/GDMLObjects.py @@ -369,7 +369,7 @@ def __init__(self, obj): #obj.setEditorMode('Placement', 2) def getMaterial(self): - return obj.material + return self.obj.material def scale(self,fp): print(f'Rescale : {fp.scale}') From b08ac6c231d059cf3088d762440aa96c73a59ac7 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Mon, 21 Mar 2022 17:44:23 +0000 Subject: [PATCH 26/45] Avoid barf on import Obj --- freecad/gdml/importOBJ.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freecad/gdml/importOBJ.py b/freecad/gdml/importOBJ.py index f7a9eff44..bf9288a91 100644 --- a/freecad/gdml/importOBJ.py +++ b/freecad/gdml/importOBJ.py @@ -170,6 +170,6 @@ def processOBJ(doc,filename) : print('Tag : '+items[0]) break - GDMLTessellated(obj,vertex,faces,'mm',getSelectedMaterial()) + GDMLTessellated(obj,vertex,faces,False,'mm',getSelectedMaterial()) ViewProvider(obj.ViewObject) obj.recompute() From de5d79b7a308409851cdb93dff6cac0710ddd12f Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Wed, 23 Mar 2022 20:26:55 +0000 Subject: [PATCH 27/45] Fix import OBJ --- freecad/gdml/GDMLObjects.py | 45 ++++++++++++++++++++++++++++++++----- freecad/gdml/GDMLShared.py | 18 --------------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/freecad/gdml/GDMLObjects.py b/freecad/gdml/GDMLObjects.py index c2228f381..366158154 100644 --- a/freecad/gdml/GDMLObjects.py +++ b/freecad/gdml/GDMLObjects.py @@ -3414,7 +3414,24 @@ def createShape(self, vertex, facets, flag): # print('Facet') # print(f) if flag is True: - FCfaces.append(GDMLShared.facet(f)) + #FCfaces.append(GDMLShared.facet(f)) + if len(f.Points) == 3: + face = GDMLShared.triangle(triangle(f.Points[0], \ + f.Points[1], f.Points[2])) + FCfaces.append(face) + else : # Four points might be close to but not coplanar OBJ file + try: + face = GDMLShared.quad(f.Points[0], f.Points[1], \ + f.Points[2], f.Points[3]) + FCfaces.append(face) + except: + print('Four points not coplanar use 2 triangular faces') + face = GDMLShared.triangle(f.Points[0], f.Points[1], \ + f.Points[2]) + FCfaces.append(face) + face = GDMLShared.triangle(f.Points[1], f.Points[2], \ + f.Points[3]) + FCfaces.append(face) else: if len(f) == 3: FCfaces.append(GDMLShared.triangle( @@ -3422,11 +3439,27 @@ def createShape(self, vertex, facets, flag): mul*vertex[f[1]], mul*vertex[f[2]])) else: # len should then be 4 - FCfaces.append(GDMLShared.quad( - mul*vertex[f[0]], - mul*vertex[f[1]], - mul*vertex[f[2]], - mul*vertex[f[3]])) + try: + face = GDMLShared.quad( + mul*vertex[f[0]], + mul*vertex[f[1]], + mul*vertex[f[2]], + mul*vertex[f[3]]) + FCfaces.append(face) + + except: # quad may not be coplanar OBJ file + print('Four points not coplanar use 2 triangular faces') + face = GDMLShared.triangle( + mul*vertex[f[0]], + mul*vertex[f[1]], + mul*vertex[f[2]]) + FCfaces.append(face) + face = GDMLShared.triangle( + mul*vertex[f[1]], + mul*vertex[f[2]], + mul*vertex[f[3]]) + FCfaces.append(face) + shell = Part.makeShell(FCfaces) shell = Part.makeShell(FCfaces) if shell.isValid is False: FreeCAD.Console.PrintWarning('Not a valid Shell/n') diff --git a/freecad/gdml/GDMLShared.py b/freecad/gdml/GDMLShared.py index 7846d8138..4f5db8ad2 100644 --- a/freecad/gdml/GDMLShared.py +++ b/freecad/gdml/GDMLShared.py @@ -555,24 +555,6 @@ def getVertex(v): return(FreeCAD.Vector(x, y, z)) -def facet(f): - # vec = FreeCAD.Vector(1.0,1.0,1.0) - # print(f"Facet {f}") - # print(f.Points) - if len(f.Points) == 3: - return(triangle(f.Points[0], f.Points[1], f.Points[2])) - # if f.Normal.dot(vec) > 0 : - # return(triangle(f.Points[0],f.Points[1],f.Points[2])) - # else : - # return(triangle(f.Points[2],f.Points[1],f.Points[0])) - else: - return(quad(f.Points[0], f.Points[1], f.Points[2], f.Points[3])) - # if f.Normal.dot(vec) > 0 : - # return(quad(f.Points[0],f.Points[1],f.Points[2],f.Points[3])) - # else : - # return(quad(f.Points[3],f.Points[2],f.Points[1],f.Points[0])) - - def triangle(v1, v2, v3): # passed vertex return face # print('v1 : '+str(v1)+' v2 : '+str(v2)+' v3 : '+str(v3)) From 56c85b0ea0aa0a69dee44234dbb712a227e81d2b Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Thu, 24 Mar 2022 21:29:48 +0000 Subject: [PATCH 28/45] convertObj --- Utils | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Utils b/Utils index e41bc6839..3708b43ef 160000 --- a/Utils +++ b/Utils @@ -1 +1 @@ -Subproject commit e41bc6839b7231ad1007fee3976d27df1fb3b565 +Subproject commit 3708b43ef735406755828c59b9c8f2ba93dc300e From 3d3cf5bed766abf095588cdb1c6a31cd05faca04 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Thu, 24 Mar 2022 21:50:59 +0000 Subject: [PATCH 29/45] Add CommandLine directory --- CommandLine/combineGDML.py | 16 +++ CommandLine/convertObj.py | 262 +++++++++++++++++++++++++++++++++++++ CommandLine/extractVol.py | 174 ++++++++++++++++++++++++ CommandLine/listSolids.py | 22 ++++ CommandLine/listVols.py | 18 +++ 5 files changed, 492 insertions(+) create mode 100644 CommandLine/combineGDML.py create mode 100644 CommandLine/convertObj.py create mode 100644 CommandLine/extractVol.py create mode 100644 CommandLine/listSolids.py create mode 100644 CommandLine/listVols.py diff --git a/CommandLine/combineGDML.py b/CommandLine/combineGDML.py new file mode 100644 index 000000000..cea783ca0 --- /dev/null +++ b/CommandLine/combineGDML.py @@ -0,0 +1,16 @@ +import sys + +print('Utility to combined a GDML files included XML files') +if len(sys.argv)<3: + print ("Usage: sys.argv[0] ") + sys.exit(1) + +iname=sys.argv[1] +oname=sys.argv[2] + +from lxml import etree +parser = etree.XMLParser(resolve_entities=True) +root= etree.parse(iname, parser=parser) +root.docinfo.clear() +root.write(oname) + diff --git a/CommandLine/convertObj.py b/CommandLine/convertObj.py new file mode 100644 index 000000000..fab1cbca8 --- /dev/null +++ b/CommandLine/convertObj.py @@ -0,0 +1,262 @@ +# ************************************************************************** +# * * +# * Copyright (c) 2022 Keith Sloan * +# * * +# * 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 * +# * * +# * * +# *************************************************************************** +__title__ = "convertOBJ - Covert Obj to GDML Tessellated" +__author__ = "Keith Sloan " +__url__ = ["https://github.com/KeithSloan/GDML/Utils"] + +import os, sys + +class switch(object): + value = None + def __new__(class_, value): + class_.value = value + return True + +def case(*args): + return any((arg == switch.value for arg in args)) + +class tessellated: + def __init__(self, gdmlStr, name): + self.tess = gdmlStr.defineTessellated(name) + + def addTriFace(self, vrt1, vrt2, vrt3): + ET.SubElement(self.tess,'triangular',{ + 'vertex1' : vrt1, 'vertex2' : vrt2, 'vertex3' : vrt3, + 'type':'ABSOLUTE'}) + + def addQuadFace(self, vrt1, vrt2, vrt3, vrt4): + ET.SubElement(self.tess,'quadrangular',{ + 'vertex1' : vrt1, 'vertex2' : vrt2, 'vertex3' : vrt3, 'vertex4': vrt4, + 'type':'ABSOLUTE'}) + +class xmlStructure: + def __init__(self): + self.vertex = ['dummy'] + + def indent(self, elem, level=0): + ######################################################### + # Pretty format GDML # + ######################################################### + i = "\n" + level*" " + j = "\n" + (level-1)*" " + if len(elem): + if not elem.text or not elem.text.strip(): + elem.text = i + " " + if not elem.tail or not elem.tail.strip(): + elem.tail = i + for subelem in elem: + self.indent(subelem, level+1) + if not elem.tail or not elem.tail.strip(): + elem.tail = j + else: + if level and (not elem.tail or not elem.tail.strip()): + elem.tail = j + + def initGDML(self): + NS = 'http://www.w3.org/2001/XMLSchema-instance' + location_attribute = '{%s}noNamespaceSchemaLocation' % NS + self.element = ET.Element('gdml',attrib={location_attribute: \ + 'http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd'}) + #print(self.element.tag) + #'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance", + #'xsi:noNamespaceSchemaLocation': "http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd" +#} + + def init(self): + self.define = ET.SubElement(self.element, 'define') + ET.SubElement(self.define, 'position', {'name':'center', 'x':'0', 'y':'0', 'z':'0'}) + ET.SubElement(self.define, 'rotation', {'name':'identity', 'x':'0', 'y':'0', 'z':'0'}) + self.defineCount = 0 + self.vertexCount = 0 + self.materials = ET.SubElement(self.element, 'materials') + self.solids = ET.SubElement(self.element, 'solids') + self.structure = ET.SubElement(self.element, 'structure') + self.setup = ET.SubElement(self.element, 'setup', {'name': 'Default', 'version': '1.0'}) + + + def addWorldBox(self, x, y, z): + name = 'worldBox' + ET.SubElement(self.solids, 'box', {'name': name, \ + 'x': str(x), 'y': str(y), 'z': str(z)}) + return name + + def addWorldVol(self,name): + ET.SubElement(self.setup, 'world', {'ref': name}) + return(self.addVol(name, 'G4_AIR',self.addWorldBox(1000,1000,1000))) + + def addVol(self, name, material, solid): + vol = ET.SubElement(self.structure, 'volume',{'name': name}) + ET.SubElement(vol, 'materialref',{'ref': material}) + ET.SubElement(vol, 'solidref',{'ref': solid}) + return vol + + def addPhysVol(self, vol, name): + pvol = ET.SubElement(vol,'physvol', {'name': 'PV'+name}) + ET.SubElement(pvol, 'volumeref', {'ref': name}) + ET.SubElement(pvol, 'positionref', {'ref': 'center'}) + ET.SubElement(pvol, 'rotationref', {'ref': 'identity'}) + + + def addVertex(self, x, y, z): + # Add to Define position name + vnum = 'v'+str(self.defineCount) + self.defineCount += 1 + self.vertexCount += 1 + ET.SubElement(self.define, 'position', {'name': vnum, \ + 'x': str(x), 'y': str(y), 'z': str(z)}) + self.vertex.append(vnum) + + def addTriFace(self, tess, items): + tess.addTriFace(self.vertex[int(items[1])], \ + self.vertex[int(items[2])], \ + self.vertex[int(items[3])]) + + def addQuadFace(self, tess, items): + tess.addQuadFace(self.vertex[int(items[1])], \ + self.vertex[int(items[2])], \ + self.vertex[int(items[3])], \ + self.vertex[int(items[4])]) + + def defineTessellated(self, name): + # return Tessellated Element + return ET.SubElement(self.solids,'tessellated',{'name': name}) + + def writeElement(self, path): + print('Write Element to : '+path) + self.indent(self.element) + ET.ElementTree(self.element).write(path, xml_declaration=True) + +def processObjFile(xmlStr, objFp, name): + tess = tessellated(xmlStr, name) + for line in objFp: + #print(line) + items = line.split(' ') + l = len(items) - 1 + while switch(items[0]) : + if case('v') : + #print('Vertex - len : '+str(l)) + if l >= 3: + xmlStr.addVertex(items[1], items[2],items[3]) + else : + print('Invalid Vertex') + print(items) + break + + if case('f') : + #print('Face') + #print(xmlStr.vertexCount) + if l == 3 : + #print('Triangle') + xmlStr.addTriFace(tess, items) + elif l == 4 : + #print('Quad : '+str(items)) + xmlStr.addQuadFace(tess, items) + else : + print('Warning Polygon : Number of Face Vertex = '+str(l)) + print('Converting to Triangle Faces') + #verts = [] + #for i in range(1,l+1) : + # v = vertex[getVert(items[i])] + # #print(v) + # verts.append(v) + ##print(verts) + #verts.append(verts[0]) + break + + if case('#') : # Comment ignore + break + + if case('vt') : + break + + if case('vn') : + break + + print('Tag : '+items[0]) + break + +def convert2GDML(objFp, outPath, tessName, material): + print('Creating GDML from Obj') + gdmlStr = xmlStructure() + gdmlStr.initGDML() + gdmlStr.init() + tessVol = gdmlStr.addVol('LV_'+tessName, material, tessName) + worldVol = gdmlStr.addWorldVol('worldVol') + gdmlStr.addPhysVol(worldVol, 'LV_'+tessName) + processObjFile(gdmlStr, objFp, tessName) + gdmlStr.writeElement(outPath) + +def convert2XML(objFp, outPath, tessName, material): + print('Creating XML from Obj') + xmlStr = xmlStructure() + xmlStr.initXML() + xmlStr.init() + processObjFile(xmlStr, objFp, tessName) + gdmlStr.writeElement(outPath) + +argLen = len(sys.argv) +if argLen<3: + print ("Usage: sys.argv[0] .obj .gdml ") + sys.exit(1) + +iPath = sys.argv[1] +oPath = sys.argv[2] +if argLen == 3: + material = 'G4_A-150_TISSUE' +else: + material = sys.argv[3] +print('\nConverting Obj file : '+iPath+' to : '+oPath) +print('Material '+material) +objFp = open(iPath) + +try: + import lxml.etree as ET + print("running with lxml.etree\n") + XML_IO_VERSION = 'lxml' +except ImportError: + try: + import xml.etree.ElementTree as ET + print("running with xml.etree.ElementTree\n") + XML_IO_VERSION = 'xml' + except ImportError: + print('xml lib not found\n') + sys.exit() +path, fileExt = os.path.splitext(iPath) +print(path) +tessName = path +print(tessName) +if fileExt.lower() != '.obj': + print('Invalid Obj file extension') + sys.exit() +objFp = open(iPath,"r") +if objFp == None: + print('Failed to open :'+iPath) + sys.exit() +path, fileExt = os.path.splitext(oPath) +print('target file extension : '+fileExt) +if fileExt.lower() == '.gdml': + convert2GDML(objFp, oPath, tessName, material) +#elif fileExt.lower() == '.xml': +# convert2XML(objFp, oPath, tessName, material) +else: + print('Target path should have File extension of gdml or xml') diff --git a/CommandLine/extractVol.py b/CommandLine/extractVol.py new file mode 100644 index 000000000..2fc1679e6 --- /dev/null +++ b/CommandLine/extractVol.py @@ -0,0 +1,174 @@ +import sys, os +from lxml import etree + +volList = [] +solidList = [] +positionList = [] +rotationList = [] + +def processSolid(sname) : + # Passed olid name volume, booleans + global solidList, solids + solid = oldSolids.find(f"*[@name='{sname}']") + print('Adding : '+sname) + print(solid.attrib) + if sname not in solidList : solidList.append(sname) + if solid.tag == 'subtraction' or solid.tag == 'union' or \ + solid.tag == 'intersection' : + print('Found Boolean') + first = solid.find('first') + print('first : '+str(first.attrib)) + fname = first.attrib.get('ref') + processSolid(fname) + second = solid.find('second') + print('second : '+str(second.attrib)) + sname = second.attrib.get('ref') + processSolid(sname) + +def processPhysVol(volasm): + for pv in volasm.findall('physvol') : + volref = pv.find('volumeref') + pname = volref.attrib.get('ref') + print('physvol : '+pname) + processVolAsm(pname) + posref = pv.find('positionref') + if posref is not None : + posname = posref.attrib.get('ref') + print('Position ref : '+posname) + if posname not in positionList : + positionList.append(posname) + rotref = pv.find('rotationref') + if rotref is not None : + rotname = rotref.attrib.get('ref') + print('Rotation ref : '+rotname) + if rotname not in rotationList : rotationList.append(rotname) + +def processVol(vol) : + global volList, solidList, oldSolids + print(vol) + print(vol.attrib) + # Need to process physvols first + processPhysVol(vol) + vname = vol.attrib.get('name') + print('volume : ' + vname) + if vname not in volList : volList.append(vname) + solid = vol.find('solidref') + sname = solid.attrib.get('ref') + processSolid(sname) + material = vol.find('materialref') + if material is not None : + #print('material : '+str(material.attrib)) + print('material : ' + material.attrib.get('ref')) + +def processAssembly(assem) : + aname = assem.attrib.get('name') + print('Process Assembly ; '+aname) + processPhysVol(assem) + if aname not in volList : volList.append(aname) + +def processVolAsm(vaname) : + volasm = structure.find(f"*[@name='{vaname}']") + if volasm.tag == 'volume' : + processVol(volasm) + elif volasm.tag == 'assembly' : + processAssembly(volasm) + else : + print('Not Volume or Assembly : '+volasm.tag) + +def exportElement(dirPath, elemName, elem) : + import os + global gdml, docString + + etree.ElementTree(elem).write(os.path.join(dirPath,elemName)) + docString += '\n' + gdml.append(etree.Entity(elemName)) + +def checkDirectory(path) : + if not os.path.exists(path): + print('Creating Directory : '+path) + os.mkdir(path) + +if len(sys.argv)<5: + print ("Usage: sys.argv[0] ") + print("/n For parms the following are or'ed together") + print(" For future") + sys.exit(1) + +parms = int(sys.argv[1]) +gdml = etree.Element('gdml') + +volume = sys.argv[2] +iName = sys.argv[3] +oName = sys.argv[4] + +print('\nExtracting Volume : '+volume+' from : '+iName+' to '+oName) +tree = etree.parse(iName) +root = tree.getroot() +structure = tree.find('structure') +oldSolids = tree.find('solids') +#print(etree.fromstring(structure)) +# Following works +#vol = structure.find('volume[@name="World"]') +# Test if Volume +vol = structure.find(f"volume[@name='{volume}']") +if vol is not None : + processVol(vol) +else : + # Test if Assembly + vol = structure.find(f"assembly[@name='{volume}']") + if vol is not None : + processAssembly(vol) + else : + print(volume+' : Not found as Volume or Assembly') + exit(0) +newDefine = etree.Element('define') +materials = tree.find('materials') +newSolids = etree.Element('solids') +newStructure = etree.Element('structure') +oldDefine = tree.find('define') +oldSolids = tree.find('solids') +oldVols = tree.find('structure') +for posName in positionList : + p = oldDefine.find(f"position[@name='{posName}']") + newDefine.append(p) +for rotName in rotationList : + p = oldDefine.find(f"rotation[@name='{rotName}']") + newDefine.append(p) +for solidName in solidList : + print('Solid : '+solidName) + s = oldSolids.find(f"*[@name='{solidName}']") + #print(s.attrib) + newSolids.append(s) +for vaName in volList : + v = oldVols.find(f"*[@name='{vaName}']") + newStructure.append(v) + +print('Vol List') +print(volList) +print('Solid List') +print(solidList) +print('Position List') +print(positionList) +print('Rotation List') +print(rotationList) +setup = etree.Element('setup', {'name':'Default', 'version':'1.0'}) +etree.SubElement(setup,'world', { 'ref' : volList[-1]}) + +print("Write GDML structure to Directory") +NS = 'http://www.w3.org/2001/XMLSchema-instance' +location_attribute = '{%s}noNameSpaceSchemaLocation' % NS +gdml = etree.Element('gdml',attrib={location_attribute: \ + 'http://service-spi.web.cern.ch/service-spi/app/releases/GDML/schema/gdml.xsd'}) + +docString = '\n\n' +#indent(gdml) +etree.ElementTree(gdml).write(os.path.join(oName,volume+'.gdml'), \ + doctype=docString.encode('UTF-8')) diff --git a/CommandLine/listSolids.py b/CommandLine/listSolids.py new file mode 100644 index 000000000..301d1f3c2 --- /dev/null +++ b/CommandLine/listSolids.py @@ -0,0 +1,22 @@ +import sys +from lxml import etree + +if len(sys.argv)<2: + print ("Usage: sys.argv[0] ") + sys.exit(1) + +iname = sys.argv[1] + +print('\nParsing : '+iname+'\n') +tree = etree.parse(iname) +root = tree.getroot() +solidList = [] +for s in tree.xpath('//solids/*') : + #print(s.tag) + if s.tag not in solidList : + solidList.append(s.tag) +l = 'List of Solids in : '+iname +print(l) +print('=' * len(l)) +for i in solidList : + print(i) diff --git a/CommandLine/listVols.py b/CommandLine/listVols.py new file mode 100644 index 000000000..3f7fc06c1 --- /dev/null +++ b/CommandLine/listVols.py @@ -0,0 +1,18 @@ +import sys +from lxml import etree + +if len(sys.argv)<2: + print ("Usage: sys.argv[0] ") + sys.exit(1) + +iname = sys.argv[1] + +print('\nListing Volumes in : '+iname+'\n') +tree = etree.parse(iname) +root = tree.getroot() +s = root.find('structure') +#print(etree.tostring(s)) +for v in s.findall('volume') : + #print(etree.tostring(v)) + n = v.get('name') + print(n) From 7113e1e270393439c83c46965a9ab3f9f53e9675 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Thu, 24 Mar 2022 21:53:06 +0000 Subject: [PATCH 30/45] Add Commands --- gdml2FC.py | 31 +++++++++++++++++++++++++++++++ gdml2step.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 gdml2FC.py create mode 100644 gdml2step.py diff --git a/gdml2FC.py b/gdml2FC.py new file mode 100644 index 000000000..8fd129306 --- /dev/null +++ b/gdml2FC.py @@ -0,0 +1,31 @@ +import sys +# add folder containing FreeCAD.pyd, FreeCADGui.pyd to sys.path +#sys.path.append("C:/Program Files/FreeCAD 0.18/bin") # example for Windows +sys.path.append("/usr/lib/freecad-daily/lib") # example for Linux +sys.path.append("/usr/lib/freecad-daily/Mod") # example for Linux +#sys.path.append("/usr/lib/freecad/lib") # example for Linux +import FreeCAD +import FreeCADGui +import Part +import Draft +import Import + + +if len(sys.argv)<3: + print ("Usage: sys.argv[0] ") + sys.exit(1) + +iname=sys.argv[1] +oname=sys.argv[2] + +print('Importing : '+iname) +FreeCAD.loadFile(iname) + +#print(dir(App.ActiveDocument)) +App.ActiveDocument.saveAs(oname) + +sys.exit(0) + +print ("Error: can't find any object") +sys.exit(1) + diff --git a/gdml2step.py b/gdml2step.py new file mode 100644 index 000000000..e82c168eb --- /dev/null +++ b/gdml2step.py @@ -0,0 +1,51 @@ +import sys +# add folder containing FreeCAD.pyd, FreeCADGui.pyd to sys.path +#sys.path.append("C:/Program Files/FreeCAD 0.18/bin") # example for Windows +#sys.path.append("/usr/lib/freecad-daily/lib") # example for Linux +#sys.path.append("/usr/lib/freecad-daily/Mod") # example for Linux +#sys.path.append("/usr/lib/freecad/lib") # example for Linux +sys.path.append("/Applications/FreeCAD_0.19-B.app/Contents/Resources/lib") +sys.path.append("/Applications/FreeCAD_0.19-B.app/Contents/Resources/lib/python3.8/site-packages") # example for Mac OS + +print(sys.path) +try : + import FreeCAD +except : + print("FreeCAD module not found - Update the sys.path.append in this script") + exit(0) +import FreeCADGui +import Part +#import PySide2 +import Draft +import Import + + +if len(sys.argv)<3: + print ("Usage: sys.argv[0] ") + sys.exit(1) + +iname=sys.argv[1] +oname=sys.argv[2] + +print('Importing : '+iname) +FreeCAD.loadFile(iname) + +# iterate through all objects +for o in App.ActiveDocument.Objects: + # find root object and export the shape + #print(dir(o)) + #print(o.Name) + if o.TypeId == 'App::Part' : + #print(o.TypeId) + print('Exporting STEP file : '+oname) + print('This can be a very slow process') + print('for large files Please be patient') + #Import.export([o],"/tmp/test4.step") + Import.export([o],oname) + sys.exit(0) + +sys.exit(0) + +print ("Error: can't find any object") +sys.exit(1) + From 1f4588165b002c64277126af59be2522a5be954e Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Thu, 24 Mar 2022 21:57:02 +0000 Subject: [PATCH 31/45] remove submodule --- .gitmodules | 3 --- gdml2FC.py => CommandLine/gdml2FC.py | 0 gdml2step.py => CommandLine/gdml2step.py | 0 Utils | 1 - 4 files changed, 4 deletions(-) rename gdml2FC.py => CommandLine/gdml2FC.py (100%) rename gdml2step.py => CommandLine/gdml2step.py (100%) delete mode 160000 Utils diff --git a/.gitmodules b/.gitmodules index d62922e3d..e69de29bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "Utils"] - path = Utils - url = https://github.com/KeithSloan/GDML_Command_Line_Utils diff --git a/gdml2FC.py b/CommandLine/gdml2FC.py similarity index 100% rename from gdml2FC.py rename to CommandLine/gdml2FC.py diff --git a/gdml2step.py b/CommandLine/gdml2step.py similarity index 100% rename from gdml2step.py rename to CommandLine/gdml2step.py diff --git a/Utils b/Utils deleted file mode 160000 index 3708b43ef..000000000 --- a/Utils +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3708b43ef735406755828c59b9c8f2ba93dc300e From 0a8cca4c50eca9ad14bd1c131dc98f91f5c07c47 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Thu, 24 Mar 2022 22:00:07 +0000 Subject: [PATCH 32/45] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5108b53e8..388989ade 100644 --- a/README.md +++ b/README.md @@ -527,7 +527,7 @@ to facilitate preparation for FEM analysis ## Standalone Utilities -The standalone utilities and documentation are now in a submodule repository https://github.com/KeithSloan/GDML_Command_Line_Utils +The standalone utilities and documentation are now in a directory CommandLine In the [Utils](Utils/) directory, you'll find a python script named **`gdml2step.py`** for creating a STEP file from a GDML file. From 68d06a33c39987c2921c06999fbaadaf5e46feb6 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 29 Mar 2022 08:17:29 +0100 Subject: [PATCH 33/45] Fix convertObj.py --- CommandLine/convertObj.py | 169 +++++++++++++++++++++++--------------- 1 file changed, 105 insertions(+), 64 deletions(-) diff --git a/CommandLine/convertObj.py b/CommandLine/convertObj.py index fab1cbca8..833683dfb 100644 --- a/CommandLine/convertObj.py +++ b/CommandLine/convertObj.py @@ -36,18 +36,32 @@ def case(*args): return any((arg == switch.value for arg in args)) class tessellated: - def __init__(self, gdmlStr, name): - self.tess = gdmlStr.defineTessellated(name) + def __init__(self, name, material): + self.elem = ET.Element('tessellated',{'name':name}) + self.name = name + self.material = material + self.content = False def addTriFace(self, vrt1, vrt2, vrt3): - ET.SubElement(self.tess,'triangular',{ + ET.SubElement(self.elem,'triangular',{ 'vertex1' : vrt1, 'vertex2' : vrt2, 'vertex3' : vrt3, 'type':'ABSOLUTE'}) + self.content = True def addQuadFace(self, vrt1, vrt2, vrt3, vrt4): - ET.SubElement(self.tess,'quadrangular',{ + ET.SubElement(self.elem,'quadrangular',{ 'vertex1' : vrt1, 'vertex2' : vrt2, 'vertex3' : vrt3, 'vertex4': vrt4, 'type':'ABSOLUTE'}) + self.content = True + + def flush(self, xmlStr): + if self.content == True: + xmlStr.solids.insert(1,self.elem) + lvName = 'LV_'+self.name + xmlStr.addVol(lvName, self.material, self.name) + xmlStr.addPhysVol(self.name) + self.content = False + class xmlStructure: def __init__(self): @@ -102,20 +116,20 @@ def addWorldBox(self, x, y, z): def addWorldVol(self,name): ET.SubElement(self.setup, 'world', {'ref': name}) - return(self.addVol(name, 'G4_AIR',self.addWorldBox(1000,1000,1000))) + self.world = self.addVol(name, 'G4_AIR',self.addWorldBox(1000,1000,1000)) def addVol(self, name, material, solid): - vol = ET.SubElement(self.structure, 'volume',{'name': name}) - ET.SubElement(vol, 'materialref',{'ref': material}) - ET.SubElement(vol, 'solidref',{'ref': solid}) - return vol - - def addPhysVol(self, vol, name): - pvol = ET.SubElement(vol,'physvol', {'name': 'PV'+name}) - ET.SubElement(pvol, 'volumeref', {'ref': name}) - ET.SubElement(pvol, 'positionref', {'ref': 'center'}) - ET.SubElement(pvol, 'rotationref', {'ref': 'identity'}) + self.elem = ET.Element('volume',{'name': name}) + ET.SubElement(self.elem, 'materialref',{'ref': material}) + ET.SubElement(self.elem, 'solidref',{'ref': solid}) + self.structure.insert(0,self.elem) + return(self.elem) + def addPhysVol(self, name): + self.pvol = ET.SubElement(self.world,'physvol', {'name': 'PV'+name}) + ET.SubElement(self.pvol, 'volumeref', {'ref': 'LV_'+name}) + ET.SubElement(self.pvol, 'positionref', {'ref': 'center'}) + ET.SubElement(self.pvol, 'rotationref', {'ref': 'identity'}) def addVertex(self, x, y, z): # Add to Define position name @@ -137,73 +151,100 @@ def addQuadFace(self, tess, items): self.vertex[int(items[3])], \ self.vertex[int(items[4])]) - def defineTessellated(self, name): - # return Tessellated Element - return ET.SubElement(self.solids,'tessellated',{'name': name}) - def writeElement(self, path): print('Write Element to : '+path) self.indent(self.element) ET.ElementTree(self.element).write(path, xml_declaration=True) -def processObjFile(xmlStr, objFp, name): - tess = tessellated(xmlStr, name) +def processObjFile(xmlStr, objFp, name, material): + xmlStr.addWorldVol('worldVol') + tessName = name + tess = tessellated(tessName, material) for line in objFp: #print(line) - items = line.split(' ') - l = len(items) - 1 - while switch(items[0]) : - if case('v') : - #print('Vertex - len : '+str(l)) - if l >= 3: - xmlStr.addVertex(items[1], items[2],items[3]) - else : - print('Invalid Vertex') - print(items) - break + items = line.split() + if items != []: + #print(items) + l = len(items) - 1 + while switch(items[0]) : + if case('v'): + #print('Vertex - len : '+str(l)) + if l >= 3: + xmlStr.addVertex(items[1], items[2],items[3]) + else: + print('Invalid Vertex') + print(items) + break - if case('f') : - #print('Face') - #print(xmlStr.vertexCount) - if l == 3 : - #print('Triangle') - xmlStr.addTriFace(tess, items) - elif l == 4 : - #print('Quad : '+str(items)) - xmlStr.addQuadFace(tess, items) - else : - print('Warning Polygon : Number of Face Vertex = '+str(l)) - print('Converting to Triangle Faces') - #verts = [] - #for i in range(1,l+1) : - # v = vertex[getVert(items[i])] - # #print(v) - # verts.append(v) - ##print(verts) - #verts.append(verts[0]) - break + if case('f'): + #print('Face') + #print(xmlStr.vertexCount) + if l == 3: + #print('Triangle') + xmlStr.addTriFace(tess, items) + elif l == 4: + #print('Quad : '+str(items)) + xmlStr.addQuadFace(tess, items) + else : + print('Warning Polygon : Number of Face Vertex = '+str(l)) + print('Converting to Triangle Faces') + #verts = [] + #for i in range(1,l+1) : + # v = vertex[getVert(items[i])] + # #print(v) + # verts.append(v) + ##print(verts) + #verts.append(verts[0]) + break - if case('#') : # Comment ignore - break + if case('g'): + print('Group Name') + tessName = items[1] + print(items) + break - if case('vt') : - break + if case('o'): + print('Object Name') + print(items) + tessName = items[1] + break + + if case('s'): + print('Smoothing Group') + tess.flush(xmlStr) + tess = tessellated(tessName, material) + break + + if case('usemtlo'): + print('Material') + print(items) + break + + if case('mtllib'): + print('Material Library') + print(items) + break + + if case('#'): # Comment ignore + break + + if case('vt'): + break + + if case('vn'): + break - if case('vn') : + print('Tag : '+str(items)) break - print('Tag : '+items[0]) - break + tess.flush(xmlStr) def convert2GDML(objFp, outPath, tessName, material): print('Creating GDML from Obj') gdmlStr = xmlStructure() gdmlStr.initGDML() gdmlStr.init() - tessVol = gdmlStr.addVol('LV_'+tessName, material, tessName) - worldVol = gdmlStr.addWorldVol('worldVol') - gdmlStr.addPhysVol(worldVol, 'LV_'+tessName) - processObjFile(gdmlStr, objFp, tessName) + processObjFile(gdmlStr, objFp, tessName, material) gdmlStr.writeElement(outPath) def convert2XML(objFp, outPath, tessName, material): @@ -211,7 +252,7 @@ def convert2XML(objFp, outPath, tessName, material): xmlStr = xmlStructure() xmlStr.initXML() xmlStr.init() - processObjFile(xmlStr, objFp, tessName) + processObjFile(xmlStr, objFp, tessName, material) gdmlStr.writeElement(outPath) argLen = len(sys.argv) From 71406de892eed245e5895b9a07edad0c9d3a4515 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 29 Mar 2022 14:31:34 +0100 Subject: [PATCH 34/45] test gmsh-dev --- metadata.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/metadata.txt b/metadata.txt index 50559ffab..a8c459500 100644 --- a/metadata.txt +++ b/metadata.txt @@ -1,2 +1,2 @@ -workbenches=Part,Mesh -pylibs=lxml,gmsh +workbenches=Part, Mesh +pylibs=lxml, gmsh-dev From 0ecacd0f6cc5e409e182824f4ac7b8d6591b194e Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 29 Mar 2022 15:13:58 +0100 Subject: [PATCH 35/45] Fix Tess --- freecad/gdml/GDMLObjects.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freecad/gdml/GDMLObjects.py b/freecad/gdml/GDMLObjects.py index 366158154..2ca31a974 100644 --- a/freecad/gdml/GDMLObjects.py +++ b/freecad/gdml/GDMLObjects.py @@ -3416,8 +3416,8 @@ def createShape(self, vertex, facets, flag): if flag is True: #FCfaces.append(GDMLShared.facet(f)) if len(f.Points) == 3: - face = GDMLShared.triangle(triangle(f.Points[0], \ - f.Points[1], f.Points[2])) + face = GDMLShared.triangle(f.Points[0], \ + f.Points[1], f.Points[2]) FCfaces.append(face) else : # Four points might be close to but not coplanar OBJ file try: From 2cfbe041e3f7f03191d894a3018f9ef1a3c79360 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Sat, 2 Apr 2022 19:11:35 +0100 Subject: [PATCH 36/45] Reset Materials --- freecad/gdml/GDMLCommands.py | 17 +++++++++++++---- freecad/gdml/GDMLMaterials.py | 3 +++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/freecad/gdml/GDMLCommands.py b/freecad/gdml/GDMLCommands.py index 4fd1d92e8..26c61ec4a 100644 --- a/freecad/gdml/GDMLCommands.py +++ b/freecad/gdml/GDMLCommands.py @@ -219,7 +219,11 @@ def initUI(self): obj = self.SelList[0].Object if hasattr(obj, 'material'): mat = obj.material - self.lineedit.setText(mat) + if mat in self.matList : # Check valid material in list + self.lineedit.setText(mat) + else : + print(f'Default to {self.materialComboBox.currentText()}') + self.lineedit.setText(self.materialComboBox.currentText()) self.setMaterial(mat) self.show() @@ -240,10 +244,12 @@ def completionActivated(self, text): def groupChanged(self, index): from .GDMLObjects import GroupedMaterials + print('Group Change') self.materialComboBox.blockSignals(True) self.materialComboBox.clear() group = self.groupsCombo.currentText() self.materialComboBox.addItems(GroupedMaterials[group]) + self.lineedit.setText(self.materialComboBox.currentText()) self.materialComboBox.blockSignals(False) def materialChanged(self, text): @@ -259,12 +265,15 @@ def onSet(self): print(f'Set Material {mat}') for sel in self.SelList: obj = sel.Object - if hasattr(obj, 'material'): - obj.material = mat - else: + if not hasattr(obj, 'material'): # Make sure obj has material prop obj.addProperty("App::PropertyEnumeration", "material", "GDML", "Material") + if obj.material.find(mat) == True: + obj.material = mat + else: + print('Reset Materials list') obj.material = self.matList + print(f'Set Material to {mat}') obj.material = self.matList.index(mat) diff --git a/freecad/gdml/GDMLMaterials.py b/freecad/gdml/GDMLMaterials.py index 8c527e2b8..77243c061 100644 --- a/freecad/gdml/GDMLMaterials.py +++ b/freecad/gdml/GDMLMaterials.py @@ -104,11 +104,13 @@ def newGetGroupedMaterials(): if len(GroupedMaterials) == 0: doc = FreeCAD.activeDocument() if not hasattr(doc, 'Materials') or not hasattr(doc, 'G4Materials'): + print('Reload Geant4 Materials') processGEANT4(doc, joinDir("Resources/Geant4Materials.xml")) docG4Materials = doc.G4Materials if not hasattr(docG4Materials, 'version'): refreshG4Materials(doc) docG4Materials = doc.G4Materials + print('Build Materials SubGroups') for g in docG4Materials.Group: # print(f'g : {g.Label}') for s in g.Group: @@ -117,6 +119,7 @@ def newGetGroupedMaterials(): GroupedMaterials[g.Label].append(s.Label) else: GroupedMaterials[g.Label] = [s.Label] + print('Build Non Geant4 Materials') matList = [] docMaterials = doc.Materials if docMaterials is not None: From c0bbcc17d9d8a75e97848fd91a530d43a78ba9f3 Mon Sep 17 00:00:00 2001 From: luz paz Date: Sat, 2 Apr 2022 14:51:13 -0400 Subject: [PATCH 37/45] Fix misc. typos --- CommandLine/convertObj.py | 2 +- freecad/gdml/importGDML.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CommandLine/convertObj.py b/CommandLine/convertObj.py index 833683dfb..bb803ff65 100644 --- a/CommandLine/convertObj.py +++ b/CommandLine/convertObj.py @@ -20,7 +20,7 @@ # * * # * * # *************************************************************************** -__title__ = "convertOBJ - Covert Obj to GDML Tessellated" +__title__ = "convertOBJ - Convert Obj to GDML Tessellated" __author__ = "Keith Sloan " __url__ = ["https://github.com/KeithSloan/GDML/Utils"] diff --git a/freecad/gdml/importGDML.py b/freecad/gdml/importGDML.py index 305db0993..26631840f 100644 --- a/freecad/gdml/importGDML.py +++ b/freecad/gdml/importGDML.py @@ -174,7 +174,7 @@ def setDisplayMode(obj, mode): def newPartFeature(obj, name): newobj = obj.newObject("Part::FeaturePython", name) - # FreeCAD can change the name i.e. hypen to underscore + # FreeCAD can change the name i.e. hyphen to underscore # So also set the Objects Label newobj.Label = name return(newobj) @@ -182,7 +182,7 @@ def newPartFeature(obj, name): def newGroupPython(obj, name): newobj = obj.newObject("App::DocumentObjectGroupPython", name) - # FreeCAD can change the name i.e. hypen to underscore + # FreeCAD can change the name i.e. hyphen to underscore # So also set the Objects Label newobj.Label = name return(newobj) From 0626d04dc8ae85bb2d977cf7f7b0856ceb6a6b38 Mon Sep 17 00:00:00 2001 From: luz paz Date: Sat, 2 Apr 2022 14:51:53 -0400 Subject: [PATCH 38/45] Fix 'testing equality to None' --- CommandLine/convertObj.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CommandLine/convertObj.py b/CommandLine/convertObj.py index bb803ff65..67494a63c 100644 --- a/CommandLine/convertObj.py +++ b/CommandLine/convertObj.py @@ -290,7 +290,7 @@ def convert2XML(objFp, outPath, tessName, material): print('Invalid Obj file extension') sys.exit() objFp = open(iPath,"r") -if objFp == None: +if objFp is None: print('Failed to open :'+iPath) sys.exit() path, fileExt = os.path.splitext(oPath) From 9a44a93197f7aedeb16fa93d2b82038e007ccebe Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Tue, 17 May 2022 11:02:08 +0100 Subject: [PATCH 39/45] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 388989ade..d45420f86 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,10 @@ Viewing CERN's LHCBVelo.gdml using the experimental FreeCAD LinkStage3 Daily bra ## Important Notes +#### New Branch Main + +This branch will be tested with the up and coming FreeCAD 0.20 release with the view to become the Default installed branch. + #### ATTENTION WINDOWS users using FreeCAD v0.19.1 The 3rd party python dependency `lxml` should have been installed in prebuilt versions of FreeCAD. From 76a509e0e63212bf796bb9f45a0e8c3f8f700f59 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Fri, 20 May 2022 13:39:05 +0100 Subject: [PATCH 40/45] Update README.md --- README.md | 150 ++++++++++++++---------------------------------------- 1 file changed, 37 insertions(+), 113 deletions(-) diff --git a/README.md b/README.md index d45420f86..0c3ce7410 100644 --- a/README.md +++ b/README.md @@ -94,29 +94,6 @@ In order to support copies of GDML Volumes the following changes have been made ## Installation -### Prerequisites - -* FreeCAD (https://freecad.org/) -* `lxml` (bundled in to FreeCAD v0.19) -* `gmsh` python library - -### gmsh python library - -The workbench uses the gmsh python library and must be installed in a location that FreeCAD sees - -To check path FreeCAD uses from a command line/window. - - freecad -c - import sys - print(sys.path) - -In a command window / line - - pip install --upgrade --target gmsh - -Windows: if no --target option upgrade pip - - ### Install via the Addon Manager The GDML workbench can be installed via the [Addon Manager](https://wiki.freecad.org/Std_AddonMgr) @@ -125,73 +102,52 @@ The GDML workbench can be installed via the [Addon Manager](https://wiki.freecad 2. Click the `Tools` → `Addon manager` dropdown menu 3. Browse through the list of workbench and look for GDML -### Prerequisite 3rd party Python libraries - -
-Click to expand! - -Currently there are two 3rd party libraries that are necessary for the GDML workbench to function: `lxml` and `gmsh`. - -#### `lxml` - -[lxml](https://lxml.de/) is a Python library that processes XML and HTML. Starting with the below versions of FreeCAD, `lxml` should be auto-bundled as part of the installation: - - * `FreeCAD_0.19.19424` and above - * `FreeCAD_0.19.19409_x64_Conda_Py3QT5-WinVS2015.7z` and above. - - -##### Checking if `lxml` is installed - -To discover if **`lxml`** is installed and accessible by FreeCAD: - -1. Open the CLI -2. Invoke the following: - ```python - freecad -c - import sys - print(sys.path) - ``` - Result: - - -**Note:** To check if **`lxml`** is installed correctly: - - ```python - freecad -c - import lxml - from lxml import etree - print(etree.LXML_VERSION) - ``` - -##### Manual install of lxml - -In case there is a need to manually install `lxml`: - - ```bash - pip3 install lxml -t < directory > - ``` - +### Prerequisites -##### FreeCAD v0.18 +* FreeCAD (https://freecad.org/) +* `lxml` (bundled in to FreeCAD v0.19) +* `gmsh` python library -There are known limitations with FreeCAD 0.18 and **lxml**. Therefore, it is recommended that you use FreeCAD v0.19 as above. -(Note: You can install both versions v0.18 & v0.19 and still use v0.18 for non GDML related work) +The Addon Manager should install the preequisite python libraries lxml and gmsh, you can check if it is successful +by from the FreeCAD python console -### `Gmsh` +* import lxml +* import gmsh -[Gmsh](https://gmsh.info/) is an open source 3D finite element mesh generator. FreeCAD & Gmsh should both be using the same version of OCC (OpenCasCade), the underlying CAD kernel that FreeCAD uses. +### gmsh shared library -| OCC | FreeCAD | gmsh | -|---------|-------------|---------------| -| `7.4` | `0.19.1` |`4.7.0 - 4.7.1`| -| `7.6` | |`4.8.0 - 4.8.4`| +Gmsh shared library is also required otherwise you will get the following error message in report View +AttributeError: dlsym(RTLD_DEFAULT, gmshInitialize): symbol not found -At the time of writing a prebuilt version of FreeCAD with OCC 7.6 is not available +To download the gmsh shared library you need to obtain a copy of the Gmsh SDK see https://gmsh.info -Note: The version of OCC with FreeCAD 0.19.2 has a regression with STEP functionality +It should then copied to FreeCAD as follows -You can check the version FreeCAD is using with About FreeCAD, copy to clipboard, paste. +#### MacOS +Copy from lib + * gmsh.py + * libgmsh.4.9.4.dylib +To : + /Applications/FreeCAD_0.20.app/Contents/Resources/lib + +#### Linux + +Copy from lib + * gmsh.py + * libgmsh.so +To : + ?????? + +#### Windows + +Copy from lib + * gmsh.py + * gmsh.lib + * gmsh-4.10.dll +To : + ?????? + #### Checking what version of Gmsh is installed To ascertain the Gmsh version, paste the following in to the python console @@ -203,38 +159,6 @@ To ascertain the Gmsh version, paste the following in to the python console gmsh.finalize() ``` -#### Check the Gmsh version using `gmshVer.py` -It is also possible to run the `gmshVer.py` script (available in this workbench's `Utils` directory). To see what versions of Gmsh are available to install, open the CLI and type: - - ```bash - pip install gmsh== - ``` - **Note:** Gmsh must be installed in a location that FreeCAD can access. To check the path FreeCAD uses, open the CLI and type: - - ```bash - freecad -c - import sys - print(sys.path) - ``` -In a command window / line - - pip install --upgrade --target gmsh=='version' - -Windows: if no --target option upgrade pip - - python -m pip install -U pip - -For example on Windows system where FreeCAD is installed on the D drive - - pip install --target="D:\FreeCAD 0.19\FreeCAD_0.19\bin\Lib\site-packages" gmsh - -will create - - D:\FreeCAD 0.19\FreeCAD_0.19\bin\Lib\site-packages\gmsh-4.6.0-py3.8.egg-info - D:\FreeCAD 0.19\FreeCAD_0.19\bin\Lib\site-packages\Lib\site-packages\gmsh-4.6.0-Windows64-sdk - -
- ## Usage * To read more about the general usage of the GDML workbench checkout the [GDML Workbench wiki](https://github.com/KeithSloan/GDML/wiki) From d6ae1094f259ca5d32901616343c6e34d04aab92 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Fri, 20 May 2022 13:46:19 +0100 Subject: [PATCH 41/45] Update README.md --- README.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0c3ce7410..a32ebc84c 100644 --- a/README.md +++ b/README.md @@ -126,27 +126,35 @@ It should then copied to FreeCAD as follows #### MacOS Copy from lib + * gmsh.py * libgmsh.4.9.4.dylib -To : + +To : + /Applications/FreeCAD_0.20.app/Contents/Resources/lib #### Linux Copy from lib + * gmsh.py * libgmsh.so -To : - ?????? +To : + + ?????? #### Windows Copy from lib + * gmsh.py * gmsh.lib * gmsh-4.10.dll -To : - ?????? + +To : + + ?????? #### Checking what version of Gmsh is installed From b7360da0089b7bab075378c765c9228287482a21 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Fri, 20 May 2022 13:48:11 +0100 Subject: [PATCH 42/45] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a32ebc84c..850341481 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,8 @@ by from the FreeCAD python console ### gmsh shared library Gmsh shared library is also required otherwise you will get the following error message in report View -AttributeError: dlsym(RTLD_DEFAULT, gmshInitialize): symbol not found + + AttributeError: dlsym(RTLD_DEFAULT, gmshInitialize): symbol not found To download the gmsh shared library you need to obtain a copy of the Gmsh SDK see https://gmsh.info From db1fd194302546e69cd0e180317e16121e4a45cc Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Sun, 19 Jun 2022 16:02:59 +0100 Subject: [PATCH 43/45] Update ReadMe for FreeCAD 0.20 --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 850341481..ec5a165eb 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,14 @@ ## FreeCAD GDML Workbench +### IMPORTANT + +FreeCAD 0.20 has been released, the default GDML workbench is now **Main** + +* Install FreeCAD 0.20 +* Delete workbench GDML +* install workbench GDML via the Addon_manager + ( use refresh Cache option to make sure latest version ) + ### Introduction **[FreeCAD](https://freecad.org)** is a Free Libre Open Source multi-platform CAD/CAM/FEM suite. From dd87d8bbc397dc9c227753eaccc8fc99524c4d01 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Sun, 19 Jun 2022 18:13:42 +0100 Subject: [PATCH 44/45] Stack --- Utils | 1 + 1 file changed, 1 insertion(+) create mode 160000 Utils diff --git a/Utils b/Utils new file mode 160000 index 000000000..10d3925eb --- /dev/null +++ b/Utils @@ -0,0 +1 @@ +Subproject commit 10d3925eb7c7b7cafebdb43beca1e0a335587300 From ae993fb8868adbd5551eb77da840058eb51d3237 Mon Sep 17 00:00:00 2001 From: Keith Sloan Date: Wed, 6 Jul 2022 18:49:10 +0100 Subject: [PATCH 45/45] Avoid gmsh-dev --- metadata.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/metadata.txt b/metadata.txt index a8c459500..9c1a4017e 100644 --- a/metadata.txt +++ b/metadata.txt @@ -1,2 +1,2 @@ workbenches=Part, Mesh -pylibs=lxml, gmsh-dev +pylibs=lxml, gmsh