diff --git a/Geodesic Domes/dome.py b/Geodesic Domes/dome.py new file mode 100644 index 0000000..821248d --- /dev/null +++ b/Geodesic Domes/dome.py @@ -0,0 +1,304 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'geodesic_dialog.ui' +# And changed manually to use FreeCAD "Gui::InputField" +# Created: Sun Jan 4 22:20:58 2015 +# by: pyside-uic 0.2.15 running on PySide 1.2.2 +# +# Upgrade 2019/06/16 for use with FreeCAD 0.19 version +#OS: Windows 10 (10.0) +#Word size of OS: 64-bit +#Word size of FreeCAD: 64-bit +#Version: 0.19.16993 (Git) +#Build type: Release +#Branch: master +#Hash: 5ea062f6699666b2f284f6a52105acf20828b481 +#Python version: 3.6.8 +#Qt version: 5.12.1 +#Coin version: 4.0.0a +#OCC version: 7.3.0 + +''' +************************************************************************ +* Copyright (c)2015 2019 Ulrich Brammer * +* * +* This file is a supplement to the FreeCAD CAx development system. * +* * +* 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 software 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 macro; if not, write to the Free Software * +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +* USA * +* * +************************************************************************ +''' + + +from PySide import QtCore, QtGui +import FreeCAD, FreeCADGui, math, Part +from FreeCAD import Base + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(477, 188) + self.dia = Dialog + self.gridLayoutWidget = QtGui.QWidget(Dialog) + self.gridLayoutWidget.setGeometry(QtCore.QRect(19, 19, 440, 141)) + self.gridLayoutWidget.setObjectName("gridLayoutWidget") + self.gridLayout = QtGui.QGridLayout(self.gridLayoutWidget) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setObjectName("gridLayout") + self.label = QtGui.QLabel(self.gridLayoutWidget) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + #self.lineEdit = QtGui.QLineEdit(self.gridLayoutWidget) + fui = FreeCADGui.UiLoader() + self.lineEdit = fui.createWidget("Gui::InputField") + + self.lineEdit.setObjectName("lineEdit") + self.gridLayout.addWidget(self.lineEdit, 0, 1, 1, 1) + self.label_2 = QtGui.QLabel(self.gridLayoutWidget) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) + self.lineEdit_2 = QtGui.QLineEdit(self.gridLayoutWidget) + self.lineEdit_2.setObjectName("lineEdit_2") + self.gridLayout.addWidget(self.lineEdit_2, 1, 1, 1, 1) + self.label_3 = QtGui.QLabel(self.gridLayoutWidget) + self.label_3.setObjectName("label_3") + self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1) + self.buttonBox = QtGui.QDialogButtonBox(self.gridLayoutWidget) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons \ + (QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 2, 1, 1, 1) + + self.retranslateUi(Dialog) + QtCore.QObject.connect(self.buttonBox, \ + QtCore.SIGNAL("accepted()"), self.makeSomething) + QtCore.QObject.connect(self.buttonBox, \ + QtCore.SIGNAL("rejected()"), self.makeNothing) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + def retranslateUi(self, Dialog): + # original code commented 2019/06/16 + # Dialog.setWindowTitle(QtGui.QApplication.translate \ + # ("Dialog", "Geodesic Dome Creator", \ + # None, QtGui.QApplication.UnicodeUTF8)) + # self.label.setText(QtGui.QApplication.translate \ + # ("Dialog", "Dome Radius", None, QtGui.QApplication.UnicodeUTF8)) + # self.label_2.setText(QtGui.QApplication.translate \ + # ("Dialog", "Frequency Parameter\n(Integer between 1 to 10)", \ + # None,QtGui.QApplication.UnicodeUTF8)) + # self.label_3.setText(QtGui.QApplication.translate \ + # ("Dialog", "This Macro creates \na full geodesic dome shell.\nX-Y-symmetry plane \nfor even frequencies", \ + # None, QtGui.QApplication.UnicodeUTF8)) + #### + # replacement code 2019/06/16 + Dialog.setWindowTitle("Geodesic Dome Creator") + self.label.setText("Dome Radius") + self.label_2.setText("Frequency Parameter\n(Integer between 1 to 10)") + self.label_3.setText("This Macro creates \na full geodesic dome shell.\nX-Y-symmetry plane \nfor even frequencies") + #### + + def makeSomething(self): + print( "accepted! Dome radius: ", self.lineEdit.property("text"), \ + " with Frequency: ", int(self.lineEdit_2.text())) + + doc=App.activeDocument() + label = "GeodesicDome" + + theDome = doc.addObject("Part::Feature",label) + radius = self.lineEdit.property("text") + frequency = int(self.lineEdit_2.text()) + + self.dia.close() + self.makeDome(theDome, radius, frequency) + doc.recompute() + + + def makeNothing(self): + print( "rejected!!") + self.dia.close() + + + + def makeDome(self, obj, domeRad_str, ny): + + def makeFreqFaces(fPt, sPt, thPt, ny = 1): + # makes the geodesic dome faces out of the points of an + # icosahedron triangle + b = self.a/ny # length of frequent triangles + # definition of direction vectors + growVec = (sPt - fPt) + # growVec = (fPt - sPt) + growVec.multiply(1.0/ny) + crossVec = (thPt - sPt) + # crossVec = (sPt - thPt) + crossVec.multiply(1.0/ny) + + for k in range(ny): + kThirdPt = fPt + growVec * (k+0.0) + dThirdPt = Base.Vector(kThirdPt.x, kThirdPt.y, kThirdPt.z) + dThirdPt = dThirdPt.normalize().multiply(domeRad.Value) + kSecPt = fPt + growVec * (k+1.0) + dSecPt = Base.Vector(kSecPt.x, kSecPt.y, kSecPt.z) + dSecPt = dSecPt.normalize().multiply(domeRad.Value) + # thirdEdge = Part.makeLine(kSecPt, kThirdPt) + # thirdEdge = Part.makeLine(dSecPt, dThirdPt) + for l in range(k+1): + firstPt = kSecPt + crossVec *(l+1.0) + dFirstPt = firstPt.normalize().multiply(domeRad.Value) + secPt = kSecPt + crossVec *(l+0.0) + dSecPt =secPt.normalize().multiply(domeRad.Value) + thirdPt = kThirdPt + crossVec *(l+0.0) + dThirdPt = thirdPt.normalize().multiply(domeRad.Value) + #thirdEdge = Part.makeLine(secPt, thirdPt) + thirdEdge = Part.makeLine(dSecPt, dThirdPt) + # Part.show(thirdEdge) + if l > 0: + print( "in l: ", l, " mod 2: ", l%2) + # What to do here? + #secEdge = Part.makeLine(oThirdPt,thirdPt) + secEdge = Part.makeLine(doThirdPt,dThirdPt) + # Part.show(secEdge) + #thirdEdge = Part.makeLine(secPt, thirdPt) + #thirdEdge = Part.makeLine(dSecPt, dThirdPt) + # Part.show(thirdEdge) + triWire = Part.Wire([firstEdge, secEdge, thirdEdge]) + # Part.show(triWire) + triFace = Part.Face(triWire) + self.domeFaces.append(triFace) + #Part.show(triFace) + + oThirdPt = thirdPt + doThirdPt = oThirdPt.normalize().multiply(domeRad.Value) + # oFirstPt = firstPt + #firstEdge = Part.makeLine(thirdPt,firstPt) + firstEdge = Part.makeLine(dThirdPt,dFirstPt) + oFirstEdge = firstEdge + #secEdge = Part.makeLine(firstPt,secPt) + secEdge = Part.makeLine(dFirstPt,dSecPt) + #Part.show(firstEdge) + #Part.show(secEdge) + #Part.show(thirdEdge) + triWire = Part.Wire([firstEdge, secEdge, thirdEdge]) + triFace = Part.Face(triWire) + self.domeFaces.append(triFace) + #Part.show(triFace) + + + domeRad = FreeCAD.Units.Quantity(domeRad_str) + + # self.a = Strutlength of underlying icosahedron: + self.a=(4.0*domeRad.Value)/math.sqrt(2.0*math.sqrt(5.0)+10.0) + + # icoAngle: angle of vertices of icosahedron points + # not a north or south pole + self.icoAngle = math.atan(0.5) + + self.icoLat = domeRad.Value * math.sin(self.icoAngle) + self.latRad = domeRad.Value * math.cos(self.icoAngle) + self.ang36 = math.radians(36.0) + + # Calculation all points of the icosahedron + self.icoPts = [] + self.icoPts.append(Base.Vector(0.0, 0.0, domeRad.Value)) + + for i in range(10): + self.icoCos = self.latRad * math.cos(i*self.ang36) + self.icoSin = self.latRad * math.sin(i*self.ang36) + if i%2 == 0: + self.icoPts.append(Base.Vector(self.icoSin, self.icoCos, self.icoLat)) + else: + self.icoPts.append(Base.Vector(self.icoSin, self.icoCos, -self.icoLat)) + + self.icoPts.append(Base.Vector(0.0, 0.0, -domeRad.Value)) + + # making the faces of the icosahedron + + self.icoFaces = [] # collects faces of the underlying icosahedron + self.domeFaces = [] # collects the faces of the geodesic dome + + thirdPt = self.icoPts[9] + thirdEdge = Part.makeLine(self.icoPts[0],thirdPt) + for i in range(5): + j = i*2+1 + firstEdge = Part.makeLine(thirdPt,self.icoPts[j]) + secEdge = Part.makeLine(self.icoPts[j],self.icoPts[0]) + triWire = Part.Wire([firstEdge, secEdge, thirdEdge]) + triFace = Part.Face(triWire) + self.icoFaces.append(triFace) + # Part.show(triFace) + makeFreqFaces(self.icoPts[j], self.icoPts[0], thirdPt, ny) + + thirdEdge = Part.makeLine(self.icoPts[0],self.icoPts[j]) + thirdPt = self.icoPts[j] + + thirdPt = self.icoPts[9] + secPt = self.icoPts[10] + thirdEdge = Part.makeLine(secPt,thirdPt) + + for i in range(10): + j = i+1 + firstEdge = Part.makeLine(thirdPt,self.icoPts[j]) + secEdge = Part.makeLine(self.icoPts[j],secPt) + triWire = Part.Wire([firstEdge, secEdge, thirdEdge]) + triFace = Part.Face(triWire) + self.icoFaces.append(triFace) + #Part.show(triFace) + makeFreqFaces(self.icoPts[j], secPt, thirdPt, ny) + + thirdPt = secPt + secPt = self.icoPts[j] + thirdEdge = Part.makeLine(secPt,thirdPt) + + + thirdPt = self.icoPts[10] + thirdEdge = Part.makeLine(self.icoPts[11],thirdPt) + for i in range(5): + j = i*2+2 + firstEdge = Part.makeLine(thirdPt,self.icoPts[j]) + secEdge = Part.makeLine(self.icoPts[j],self.icoPts[11]) + triWire = Part.Wire([firstEdge, secEdge, thirdEdge]) + triFace = Part.Face(triWire) + self.icoFaces.append(triFace) + #Part.show(triFace) + makeFreqFaces(self.icoPts[j], self.icoPts[11], thirdPt, ny) + + thirdEdge = Part.makeLine(self.icoPts[11],self.icoPts[j]) + thirdPt = self.icoPts[j] + + # Shell of a corresponding icosahedron + newShell = Part.Shell(self.icoFaces) + #Part.show(newShell) + + # Shell of the geodesic dome + #self.domeShell = Part.Shell(self.domeFaces) + #Part.show(self.domeShell) + obj.Shape = Part.Shell(self.domeFaces) + + # Shere with radius of geodesic dome for debugging purposes + testSphere = Part.makeSphere(domeRad.Value) + #Part.show(testSphere) + + +d = QtGui.QWidget() +d.ui = Ui_Dialog() +d.ui.setupUi(d) +d.ui.lineEdit_2.setText("2") +d.ui.lineEdit.setProperty("text", "2 m") + +d.show() + diff --git a/Geodesic Domes/dome_advanced.py b/Geodesic Domes/dome_advanced.py new file mode 100644 index 0000000..2cd06d2 --- /dev/null +++ b/Geodesic Domes/dome_advanced.py @@ -0,0 +1,1577 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'geodesic_dialog4.ui' +# +# Created: Sat Jan 31 19:05:50 2015 +# by: pyside-uic 0.2.15 running on PySide 1.2.2 +# +# WARNING! All changes made in this file will be lost! + +######################################################################## +# Copyright (c)2015 Ulrich Brammer # +# # +# This file is a supplement to the FreeCAD CAx development system. # +# # +# 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 software 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 macro; if not, write to the Free Software # +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 # +# USA # +# # +######################################################################## + +from PySide import QtCore, QtGui +import FreeCAD, FreeCADGui, math, Part, DraftVecUtils +from FreeCAD import Base +from collections import Counter + +class Ui_Dialog(object): + def setupUi(self, Dialog): + Dialog.setObjectName("Dialog") + Dialog.resize(550, 367) + self.dia = Dialog + FCUi = FreeCADGui.UiLoader() + self.triangles = 75 + self.nodes = 46 + self.edges = 120 + + self.gridLayoutWidget = QtGui.QWidget(Dialog) + self.gridLayoutWidget.setGeometry(QtCore.QRect(20, 20, 508, 325)) + self.gridLayoutWidget.setObjectName("gridLayoutWidget") + self.gridLayout = QtGui.QGridLayout(self.gridLayoutWidget) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setObjectName("gridLayout") + self.domeInfo1 = QtGui.QLabel(self.gridLayoutWidget) + self.domeInfo1.setObjectName("domeInfo1") + self.domeInfo1.setText(u'26 Nodes') + + self.gridLayout.addWidget(self.domeInfo1, 10, 0, 1, 1) + #self.domeBandsLE = QtGui.QLineEdit(self.gridLayoutWidget) + self.domeBandsLE = FCUi.createWidget("Gui::UIntSpinBox") + self.domeBandsLE.setObjectName("domeBandsLE") + spinBoxOffset = self.domeBandsLE.property('minimum') + self.domeBandsLE.setProperty('minimum', spinBoxOffset + 1) + self.domeBandsLE.setProperty('maximum', spinBoxOffset + 30) + self.domeBandsLE.setProperty('value', spinBoxOffset + 4) + self.gridLayout.addWidget(self.domeBandsLE, 2, 1, 1, 1) + self.domeBomCB = QtGui.QCheckBox(self.gridLayoutWidget) + self.domeBomCB.setObjectName("domeBomCB") + self.gridLayout.addWidget(self.domeBomCB, 9, 1, 1, 1) + self.domeShellCB = QtGui.QCheckBox(self.gridLayoutWidget) + self.domeShellCB.setChecked(True) + self.domeShellCB.setObjectName("domeShellCB") + self.gridLayout.addWidget(self.domeShellCB, 4, 0, 1, 1) + self.flatSegCB = QtGui.QCheckBox(self.gridLayoutWidget) + self.flatSegCB.setObjectName("flatSegCB") + self.gridLayout.addWidget(self.flatSegCB, 4, 1, 1, 1) + #self.domeRadLE = QtGui.QLineEdit(self.gridLayoutWidget) + self.domeRadLE = FCUi.createWidget("Gui::InputField") + self.domeRadLE.setObjectName("domeRadLE") + self.domeRadLE.setProperty("text", "900 mm") + + self.gridLayout.addWidget(self.domeRadLE, 0, 1, 1, 1) + self.domeFrameCB = QtGui.QCheckBox(self.gridLayoutWidget) + self.domeFrameCB.setEnabled(True) + self.domeFrameCB.setObjectName("domeFrameCB") + self.gridLayout.addWidget(self.domeFrameCB, 8, 0, 1, 1) + self.buttonBox = QtGui.QDialogButtonBox(self.gridLayoutWidget) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok) + self.buttonBox.setObjectName("buttonBox") + self.gridLayout.addWidget(self.buttonBox, 11, 1, 1, 1) + self.domeRadLab = QtGui.QLabel(self.gridLayoutWidget) + self.domeRadLab.setObjectName("domeRadLab") + self.gridLayout.addWidget(self.domeRadLab, 0, 0, 1, 1) + self.domeFreqLab = QtGui.QLabel(self.gridLayoutWidget) + self.domeFreqLab.setObjectName("domeFreqLab") + self.gridLayout.addWidget(self.domeFreqLab, 1, 0, 1, 1) + self.macroLab = QtGui.QLabel(self.gridLayoutWidget) + self.macroLab.setObjectName("macroLab") + self.gridLayout.addWidget(self.macroLab, 11, 0, 1, 1) + self.domeBandLab = QtGui.QLabel(self.gridLayoutWidget) + self.domeBandLab.setObjectName("domeBandLab") + self.gridLayout.addWidget(self.domeBandLab, 2, 0, 1, 1) + self.domeInfo2 = QtGui.QLabel(self.gridLayoutWidget) + self.domeInfo2.setObjectName("domeInfo2") + self.domeInfo2.setText(u'40 Triangles 65 Edges') + self.gridLayout.addWidget(self.domeInfo2, 10, 1, 1, 1) + #self.domeFreqLE = QtGui.QLineEdit(self.gridLayoutWidget) + self.domeFreqLE = FCUi.createWidget("Gui::UIntSpinBox") + self.domeFreqLE.setObjectName("domeFreqLE") + self.domeFreqLE.setProperty('minimum', spinBoxOffset + 1) + self.domeFreqLE.setProperty('maximum', spinBoxOffset + 10) + self.domeFreqLE.setProperty('value', spinBoxOffset + 3) + + self.gridLayout.addWidget(self.domeFreqLE, 1, 1, 1, 1) + self.strutDrawCB = QtGui.QCheckBox(self.gridLayoutWidget) + self.strutDrawCB.setObjectName("strutDrawCB") + self.gridLayout.addWidget(self.strutDrawCB, 9, 0, 1, 1) + self.strutWidthLab = QtGui.QLabel(self.gridLayoutWidget) + self.strutWidthLab.setObjectName("strutWidthLab") + self.gridLayout.addWidget(self.strutWidthLab, 5, 0, 1, 1) + self.strutHeightLab = QtGui.QLabel(self.gridLayoutWidget) + self.strutHeightLab.setObjectName("strutHeightLab") + self.gridLayout.addWidget(self.strutHeightLab, 6, 0, 1, 1) + #self.strutWidthLE = QtGui.QLineEdit(self.gridLayoutWidget) + self.strutWidthLE = FCUi.createWidget("Gui::InputField") + self.strutWidthLE.setObjectName("strutWidthLE") + self.strutWidthLE.setProperty("text", "40 mm") + + self.gridLayout.addWidget(self.strutWidthLE, 5, 1, 1, 1) + self.strutHeightLE = FCUi.createWidget("Gui::InputField") + self.strutHeightLE.setObjectName("strutHeightLE") + self.strutHeightLE.setProperty("text", "60 mm") + self.gridLayout.addWidget(self.strutHeightLE, 6, 1, 1, 1) + + + self.retranslateUi(Dialog) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), self.makeSomething) + QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), self.makeNothing) + QtCore.QObject.connect(self.domeBandsLE, QtCore.SIGNAL("valueChanged(int)"), self.updateInfo) + QtCore.QObject.connect(self.domeFreqLE, QtCore.SIGNAL("valueChanged(int)"), self.updateInfo) + QtCore.QMetaObject.connectSlotsByName(Dialog) + + + def retranslateUi(self, Dialog): + Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Geodesic Dome Creator", None)) + #self.domeBomPathLab.setText(QtGui.QApplication.translate("Dialog", "Path for BOM-File", None)) + self.domeBomCB.setText(QtGui.QApplication.translate("Dialog", "Make Bill of Materials", None)) + self.domeShellCB.setText(QtGui.QApplication.translate("Dialog", "Show Dome Shell", None)) + self.flatSegCB.setText(QtGui.QApplication.translate("Dialog", "Show Flat Segment", None)) + self.domeFrameCB.setText(QtGui.QApplication.translate("Dialog", "Show Dome Frame", None)) + self.domeRadLab.setText(QtGui.QApplication.translate("Dialog", "Dome Radius", None)) + self.domeFreqLab.setText(QtGui.QApplication.translate("Dialog", "Frequency Parameter\n" + "(Integer between 1 to 10)", None)) + self.macroLab.setText(QtGui.QApplication.translate("Dialog", "This Macro creates \n" + "a geodesic dome.\n" + "X-Y-symmetry-plane\n" + "for even frequencies", None,)) + self.domeBandLab.setText(QtGui.QApplication.translate("Dialog", "Dome Bands (3xFrequency\n" + "Parameter makes a Globe)", None)) + self.strutDrawCB.setText(QtGui.QApplication.translate("Dialog", "Make Strut Drawing", None)) + self.strutWidthLab.setText(QtGui.QApplication.translate("Dialog", "Strut Width", None)) + self.strutHeightLab.setText(QtGui.QApplication.translate("Dialog", "Strut Height", None)) + + + + def makeSomething(self): + print ("accepted! Dome radius: ", self.domeRadLE.property("text"), \ + " with Frequency: ", int(self.domeFreqLE.property("text"))) + + #doc=App.activeDocument() + + radius = self.domeRadLE.property("text") + frequency = int(self.domeFreqLE.property("text")) + myBands = int(self.domeBandsLE.property("text")) + myStrutH = self.strutHeightLE.property("text") + myStrutW = self.strutWidthLE.property("text") + + theDome = Dome(radius, frequency, myBands, myStrutH, myStrutW) + + + theDome.doShell = self.domeShellCB.isChecked() + theDome.doFlat = self.flatSegCB.isChecked() + theDome.doFrame = self.domeFrameCB.isChecked() + theDome.doStrut = self.strutDrawCB.isChecked() + theDome.doBom = self.domeBomCB.isChecked() + + self.dia.close() + #self.makeDome(theDome, radius, frequency) + theDome.makeDome() + theDome.makeNodes() + if self.triangles > 360: + myAnnoScale = 2.0 + elif self.triangles > 120: + myAnnoScale = 3.0 + else: + myAnnoScale = 5.0 + + + if theDome.doShell: theDome.showDomeShell() + if theDome.doFrame: theDome.showDomeFrame() + if theDome.doFlat or theDome.doStrut: theDome.showFlatSegment() + if theDome.doStrut: + frameDrawing = Drawing(theDome.doc, 'Drawing_Frame_Segment') + drawScale = frameDrawing.calcScale(theDome.flatFrame) + theSegment = frameDrawing.addView(theDome.flatFrame, drawScale, "Strut segment") + for strut in theDome.uFoStruts: + frameDrawing.addAnnotation2(strut.sName, strut.annoPt, theSegment, myAnnoScale) + + strutDrawing = Drawing(theDome.doc, 'Drawing_Strut') + strutDrawing.addStrutView (theDome) + + if theDome.doBom: + import Spreadsheet + if ".py" in Spreadsheet.__file__: + if ".pyd" in Spreadsheet.__file__: + theBom = Bom(theDome) + theBom.fillBom() + else: + mw=FreeCADGui.getMainWindow() + QtGui.QMessageBox.information(mw,"Info","FreeCAD Release version 0.15 needed for the Bill of Material") + else: + theBom = Bom(theDome) + theBom.fillBom() + + + theDome.doc.recompute() + App.Gui.SendMsgToActiveView("ViewFit") + #self.dia.destroy() + + + def makeNothing(self): + print ("rejected!!") + self.dia.close() + + def updateInfo(self): + + radius = self.domeRadLE.property("text") + frequency = int(self.domeFreqLE.property("text")) + myBands = int(self.domeBandsLE.property("text")) + + # calculating the parameters for makeFreqFaces / info update + self.nodes = 1 + + if myBands < frequency: + IcutTop = myBands + IcutMid = 0 + IcutBottom = 0 + else: + IcutTop = frequency + if myBands < 2*frequency: + IcutMid = myBands - frequency + IcutBottom = 0 + else: + IcutMid = frequency + if myBands < 3*frequency: + IcutBottom = myBands - 2*frequency + else: + IcutBottom = frequency + self.nodes = 2 + + # calculating the dome info data + self.triangles = 0 + halfProfileStruts = 0 + self.edges = 0 + for i in range(IcutTop): + self.triangles = self.triangles + (2*i + 1) *5 + self.nodes = self.nodes + (i + 1) *5 + self.edges = self.edges + (2 + 3*i) * 5 + + for i in range(IcutMid): + self.triangles = self.triangles + 2*frequency * 5 + self.nodes = self.nodes + frequency *5 + self.edges = self.edges + (3*frequency) * 5 + + for i in range(IcutBottom): + self.triangles = self.triangles + (2*(frequency-1-i)+1) * 5 + self.nodes = self.nodes + ((frequency-1-i)) * 5 + self.edges = self.edges + (3*(frequency-1-i)+1) * 5 + + print ("dome info triangles: ", self.triangles) + print ("dome info nodes: ", self.nodes) + print ("dome info edges: ", self.edges) + self.domeInfo2.setText(str(self.triangles)+' Triangles '+ \ + str(self.edges) + ' Edges') + self.domeInfo1.setText(str(self.nodes) + ' Nodes') + + + + +class Bom(object): + ''' Bom is a class to provide a spreadsheet-object for storing + the bill of material for a geodesic dome made of struts. + ''' + def __init__(self, myDome): + + #self.doc = myDome.doc + self.dome = myDome + self.sheet = self.dome.doc.addObject('Spreadsheet::Sheet','Bill_of_Material') + + self.actRow = 2 + self.sheet.set('A'+ str(self.actRow), myDome.domeRadQuant) + self.sheet.set('B'+ str(self.actRow), 'Radius of the Dome') + + self.actRow += 1 + self.sheet.set('A'+ str(self.actRow), myDome.strutHQuant) + self.sheet.set('B'+ str(self.actRow), 'H Height of Strutprofile') + + self.actRow += 1 + self.sheet.set('A'+ str(self.actRow), '=('+ myDome.strutWQuant+ ')/2') + self.sheet.set('B'+ str(self.actRow), 'W/2 Half-Width of Strutprofile') + + self.actRow += 2 + self.sheet.set('A'+ str(self.actRow), 'Type of Strut') + self.sheet.set('B'+ str(self.actRow), 'Amount Half-Width Profiles') + self.sheet.set('C'+ str(self.actRow), 'Strut Length') + self.sheet.set('D'+ str(self.actRow), 'Angle Gamma0') + self.sheet.set('E'+ str(self.actRow), 'Angle Gamma1') + self.sheet.set('F'+ str(self.actRow), 'Angle Beta') + self.dome.doc.recompute() + + def addRow(self, strutType, number, strutLen, gam0, gam1): + self.actRow += 1 + self.sheet.set('A'+ str(self.actRow), str(strutType)) + self.sheet.set('B'+ str(self.actRow), str(number)) + self.sheet.set('C'+ str(self.actRow), str(strutLen) + 'mm') + self.sheet.set('D'+ str(self.actRow), str(math.degrees(gam0)) + 'deg') + self.sheet.set('E'+ str(self.actRow), str(math.degrees(gam1)) + 'deg') + self.sheet.set('F'+ str(self.actRow), '=acos(C'+ str(self.actRow) +' /2/A2)') + + def fillBom(self): + print ("fillBom") + myCounts = dict(self.dome.bomCounts) + #for myKey in self.dome.strutNames: + for myKey in myCounts: + print ('addKey: ', myKey) + self.addRow(self.dome.strutNames[myKey], myCounts[myKey], \ + myKey[0], myKey[1], myKey[2]) + +class Drawing_node(object): + ''' Drawing_node is a class to store triangle Face data, needed for + an unfold process to create a flat representation of those triangles. + ''' + def __init__(self, tFace = None, normAxis = None): + self.triFace = tFace # + self.strutList = [] + self.children = [] + self.foldEdge = None + self.parent = None + self.axis = normAxis + + + +class Drawing(object): + ''' Class to store the objects for a A3-drawing page''' + def __init__(self, myDoc, dTitle): + self.doc = myDoc + self.Page = self.doc.addObject('Drawing::FeaturePage', dTitle) + self.Page.Template = App.getResourceDir()+'Mod/Drawing/Templates/A3_Landscape.svg' + self.usableX = 0 + self.usableY = 0 + self.annoCounter = 1 + + def calcScale(self, myObject): + + myShape = myObject.Shape + # Scale calculation + self.usableX = 380 + self.usableY = 240 + + rawXScale = self.usableX / myShape.BoundBox.XLength + rawYScale = self.usableY / myShape.BoundBox.YLength + if rawXScale < rawYScale: + rawScale = rawXScale + else: + rawScale = rawYScale + magnitude = math.floor(math.log10(rawScale)) + fineFactor = rawScale/(10**magnitude) + #print "fineFactor: ", fineFactorY, " YLength: ", myShape.BoundBox.YLength + if (fineFactor < 1.5): + fineFactor = 1.0 + else: + if (fineFactor < 2.5): + fineFactor = 1.5 + else: + if (fineFactor < 5.0): + fineFactor = 2.5 + else: + if (fineFactor < 7.5): + fineFactor = 5.0 + else: + fineFactor = 7.5 + return fineFactor*10**magnitude + + def addView(self, myObject, Scale, label): + myView = self.doc.addObject('Drawing::FeatureViewPart', label) + myView.Source = myObject + myView.Direction = (0.0, 0.0, 1.0) + myView.Scale = Scale + myShape = myObject.Shape + myView.X = 20 + self.usableX - (self.usableX - myView.Scale * myShape.BoundBox.XLength) / 2.0 + myView.Y = 5 + (self.usableY - myView.Scale * myShape.BoundBox.YLength) / 2.0 + self.Page.addObject(myView) + return myView + + def addStrutView(self, aDome): + ''' The first Strut of the dome is shown here''' + + myView = self.doc.addObject('Drawing::FeatureViewPart', 'Strut_A_top') + myView.Source = aDome.doc.Strut_A_ + myView.Direction = aDome.nodeDict[(0,0)].strutList[0].proDir + myShape = aDome.doc.Strut_A_.Shape + viewAngle = myView.Direction.getAngle(Base.Vector(0,0,1.0)) + + # Scale calculation + self.usableX = 380 + self.usableY = 200 + + rawXScale = self.usableX / (myShape.BoundBox.XLength / math.cos(viewAngle)) + rawYScale = self.usableY / myShape.BoundBox.YLength + if rawXScale < rawYScale: + rawScale = rawXScale + else: + rawScale = rawYScale + magnitude = math.floor(math.log10(rawScale)) + fineFactor = rawScale/(10**magnitude) + #print "fineFactor: ", fineFactorY, " YLength: ", myShape.BoundBox.YLength + if (fineFactor < 2.0): + fineFactor = 1.0 + else: + if (fineFactor < 5.0): + fineFactor = 2.0 + else: + fineFactor = 5.0 + myView.Scale = fineFactor*10**magnitude + + angleOffSet = (math.sin(viewAngle)*aDome.domeRad) * myView.Scale + cosOffSet = ((1.0-math.cos(viewAngle))*aDome.domeRad) * myView.Scale + print ("sinOff: ", angleOffSet, ' cosOff: ', cosOffSet) + + myView.X = 20 + self.usableX -angleOffSet - \ + (self.usableX - myView.Scale * myShape.BoundBox.XLength / math.cos(viewAngle)) / 2.0 + myView.Y = 15 + 150 #+ (self.usableY - myView.Scale * myShape.BoundBox.YLength) / 2.0 + myView.LineWidth = 0.75 + self.Page.addObject(myView) + + # Dimension Profile Half-Width + vec1 = aDome.doc.Strut_A_.Shape.Edge8.Vertex2.Point - \ + aDome.doc.Strut_A_.Shape.Edge8.Vertex1.Point + vec2 = aDome.doc.Strut_A_.Shape.Vertex1.Point - \ + aDome.doc.Strut_A_.Shape.Edge8.Vertex1.Point + angleGam1 = vec1.getAngle(vec2) + dimX1 = myView.X - myView.Scale * myShape.BoundBox.XLength / math.cos(viewAngle) / 2.0 + dimY1 = myView.Y + dimX2 = myView.X + aDome.strutW / 2.0 / math.tan(angleGam1) * myView.Scale + dimY2 = myView.Y + aDome.strutW / 2.0 * myView.Scale + self.addDim(dimX1, dimY1, dimX2, dimY2, -1.0, 0.0, 'W/2') + + # Dimension Gamma1 + r = 70.0 + self.addArcDim(dimX1, dimY1, angleGam1, r, '1', 'Gamma1') + + # Dimension Gamma0 + vec1 = aDome.doc.Strut_A_.Shape.Edge8.Vertex1.Point - \ + aDome.doc.Strut_A_.Shape.Edge8.Vertex2.Point + vec2 = aDome.doc.Strut_A_.Shape.Vertex2.Point - \ + aDome.doc.Strut_A_.Shape.Edge8.Vertex2.Point + r = 70.0 + dimX1 = myView.X + myView.Scale * myShape.BoundBox.XLength / math.cos(viewAngle) / 2.0 + dimY1 = myView.Y + angleGam0 = vec1.getAngle(vec2) + self.addArcDim(dimX1, dimY1, angleGam0, r, '0', 'Gamma0') + + + myView2 = self.doc.addObject('Drawing::FeatureViewPart', 'Strut_A_side') + myView2.Source = aDome.doc.Strut_A_ + myView2.Direction = Base.Vector(0.0, -1.0, 0.0) + myView2.Rotation = math.degrees(viewAngle)+90.0 + myView2.Scale = myView.Scale + myView2.LineWidth = 0.75 + #myView2.X = 20 + self.usableX - \ + # (self.usableX - myView.Scale * myShape.BoundBox.XLength) / 2.0 + myView2.X = myView.X + + heightOffSet = aDome.domeRad * myView.Scale + myView2.Y = 15 + 50 + heightOffSet - cosOffSet + self.Page.addObject(myView2) + + + annoTop = self.doc.addObject('Drawing::FeatureView','Anno_Top') + aX = myView.X + aY = myView.Y - 5 + tPos = 'center' + annoTop.ViewResult = self.addSVGText(aX, aY, 'Top-View', tPos) + self.Page.addObject(annoTop) + + + + + + + + annoSide = self.doc.addObject('Drawing::FeatureView','Anno_Side') + #annoBeta.Text = [unicode('Side-View', 'utf-8')] + #annoBeta.Scale = 5 + aX = myView.X #- myView.Scale * myShape.BoundBox.XLength / math.cos(viewAngle) / 2.0 + aY = 15 + 50 - 20 + annoSide.ViewResult = self.addSVGText(aX, aY, 'Side-View', tPos) + self.Page.addObject(annoSide) + + # Dimension Profile height + angleBeta = (math.pi - aDome.doc.Strut_A_.Shape.Edge8.Vertex1.Point.getAngle( \ + aDome.doc.Strut_A_.Shape.Edge8.Vertex2.Point)) / 2.0 + dimX1 = myView.X - myView.Scale * myShape.BoundBox.XLength / math.cos(viewAngle) / 2.0 + dimY1 = 15 + 50 + dimX2 = dimX1 + aDome.strutH / math.tan(angleBeta) * myView.Scale + dimY2 = dimY1 + aDome.strutH * myView.Scale + + self.addDim(dimX1, dimY1, dimX2, dimY2, -1.0, 0.0, 'H') + + # Dimension Profile Length + dimX1 = myView.X - myView.Scale * myShape.BoundBox.XLength / math.cos(viewAngle) / 2.0 + dimY1 = 15 + 50 + dimX2 = myView.X + myView.Scale * myShape.BoundBox.XLength / math.cos(viewAngle) / 2.0 + dimY2 = 15 + 50 + self.addDim(dimX1, dimY1, dimX2, dimY2, 0.0, -1.0, 'Length') + + + # Dimension Beta + r = 70.0 + # r = aDome.strutH * myView.Scale * 1.05 + dimX1 = myView.X - myView.Scale * myShape.BoundBox.XLength / math.cos(viewAngle) / 2.0 + dimY1 = 15 + 50 + self.addArcDim(dimX1, dimY1, angleBeta, r, '1', 'Beta') + + + + + + def addAnnotation(self, theText, anPt, theView, scale = 5.0): + #print "annoPoint: ", anPt.X, ' ', anPt.Y,' ', anPt.Z, ' View.X: ', theView.X, ' View.Y: ', theView.Y, 'Scale: ', theView.Scale + + myAnno = self.doc.addObject('Drawing::FeatureViewAnnotation','Annotation') + myAnno.Text = [unicode(theText, 'utf-8')] + myAnno.Scale = scale + myAnno.X = theView.X + anPt.X * theView.Scale - myAnno.Scale/2.0 + myAnno.Y = theView.Y - anPt.Y * theView.Scale + myAnno.Scale/2.0 + self.Page.addObject(myAnno) + + + def addAnnotation2(self, theText, anPt, theView, scale = 5.0): + #print "annoPoint: ", anPt.X, ' ', anPt.Y,' ', anPt.Z, ' View.X: ', theView.X, ' View.Y: ', theView.Y, 'Scale: ', theView.Scale + obName = 'Annota' + str(self.annoCounter) + self.annoCounter += 1 + myAnno = self.doc.addObject('Drawing::FeatureView', obName) + # myAnno.Text = [unicode(theText, 'utf-8')] + # myAnno.Scale = scale + # aX = theView.X + anPt.X * theView.Scale - myAnno.Scale/2.0 + # aY = theView.Y - anPt.Y * theView.Scale + myAnno.Scale/2.0 + aX = theView.X + anPt.X * theView.Scale + aY = theView.Y - anPt.Y * theView.Scale + myAnno.Scale*1.25 + tPos = 'center' + myAnno.ViewResult = self.addSVGText(aX, aY, theText, tPos, scale) + self.Page.addObject(myAnno) + + + + def addSVGLine(self, x1, y1, x2, y2, arrow = False): + strokeDef = '" style="stroke:#000000;stroke-width:0.30" />' + lineSVG = '' + lineSVG += '' + # textSVG += ''+ theText + '\n' + textSVG += theText + '\n' + textSVG += '\n\n' + return textSVG + + def addSVGArc(self, x1, y1, x2, y2, r, sweep): + # x1 and y1 should spezify the coordinates at the horizontal line + strokeDef = '" style="stroke:#000000;stroke-width:0.30" />' + + arcSVG = '' + arcSVG += '' + + arcSVG += '= 3*ny makes a geodesic globe + self.strutH = FreeCAD.Units.parseQuantity(strH).Value + self.strutW = FreeCAD.Units.parseQuantity(strW).Value + self.strutHQuant = strH + self.strutWQuant = strW + + + # icoAngle: angle of vertices of icosahedron points not a north or south pole + icoAngle = math.atan(0.5) + icoLat = self.domeRad * math.sin(icoAngle) + latRad = self.domeRad * math.cos(icoAngle) + ang36 = math.radians(36.0) + + + # Calculation all points of the icosahedron + self.icoPts = [] + self.icoPts.append(Base.Vector(0.0, 0.0, self.domeRad)) + + for i in range(10): + icoCos = latRad * math.cos(i*ang36 - math.pi / 2.0) + icoSin = latRad * math.sin(i*ang36 - math.pi / 2.0) + if i%2 == 0: + self.icoPts.append(Base.Vector(icoSin, icoCos, icoLat)) + else: + self.icoPts.append(Base.Vector(icoSin, icoCos, -icoLat)) + + self.icoPts.append(Base.Vector(0.0, 0.0, -self.domeRad)) + + self.domeFaces = [] + self.domeStruts = [] + + self.nodeDict = {} # Dictionary for the nodes to be unfolded + # Key = (band, triangle number in band) band starts with 0 + + + # calculating the parameter for makeFreqFaces + if self.totalBands < self.ny: + self.cutTop = self.totalBands + self.cutMid = 0 + self.cutBottom = 0 + else: + self.cutTop = self.ny + if self.totalBands < 2*self.ny: + self.cutMid = self.totalBands - self.ny + self.cutBottom = 0 + else: + self.cutMid = self.ny + if self.totalBands < 3*self.ny: + self.cutBottom = self.totalBands - 2*self.ny + else: + self.cutBottom = self.ny + + # setting the special values for ny=3 (David Kruschke partioning) + # makes a flat bottom for 4 and 5 bands with ny==3 + if self.ny == 3: + # Calculate the central point for icosahedron triangle 9, 10, 1 + # See ASCI-sketch below + # is identical to center of incircle of triangle + firstEdge = self.icoPts[9]-self.icoPts[10] + secEdge = self.icoPts[10]-self.icoPts[1] + thirdEdge = self.icoPts[1]-self.icoPts[9] + sumOfLength = firstEdge.Length + secEdge.Length + thirdEdge.Length + cIdSecPt = Base.Vector(self.icoPts[1].x, self.icoPts[1].y, self.icoPts[1].z) + cIdThirdPt = Base.Vector(self.icoPts[9].x, self.icoPts[9].y, self.icoPts[9].z) + cIdFirstPt = Base.Vector(self.icoPts[10].x, self.icoPts[10].y, self.icoPts[10].z) + centerIncircle = cIdSecPt.multiply(firstEdge.Length / sumOfLength) \ + + cIdThirdPt.multiply(secEdge.Length / sumOfLength) \ + + cIdFirstPt.multiply(thirdEdge.Length / sumOfLength) + + centerKruschke = centerIncircle.normalize().multiply(self.domeRad) + angleKruschke = math.sin(centerKruschke.z/self.domeRad) + partRatio = centerKruschke.z/self.domeRad + + + lamb=(partRatio*math.sqrt(((-self.icoPts[9].y**2-self.icoPts[9].x**2)* \ + self.icoPts[10].z**2+(2*self.icoPts[9].y*self.icoPts[9].z*self.icoPts[10].y+ \ + 2*self.icoPts[9].x*self.icoPts[9].z*self.icoPts[10].x)*self.icoPts[10].z+\ + (-self.icoPts[9].z**2-self.icoPts[9].x**2)*self.icoPts[10].y**2+\ + 2*self.icoPts[9].x*self.icoPts[9].y*self.icoPts[10].x*self.icoPts[10].y+\ + (-self.icoPts[9].z**2-self.icoPts[9].y**2)*self.icoPts[10].x**2)*partRatio**2+\ + (self.icoPts[9].y**2+self.icoPts[9].x**2)*self.icoPts[10].z**2+\ + (-2*self.icoPts[9].y*self.icoPts[9].z*self.icoPts[10].y-2*self.icoPts[9].x*\ + self.icoPts[9].z*self.icoPts[10].x)*self.icoPts[10].z+self.icoPts[9].z**2*\ + self.icoPts[10].y**2+self.icoPts[9].z**2*self.icoPts[10].x**2)+\ + (-self.icoPts[9].z*self.icoPts[10].z-self.icoPts[9].y*self.icoPts[10].y-\ + self.icoPts[9].x*self.icoPts[10].x+self.icoPts[9].z**2+self.icoPts[9].y**2+\ + self.icoPts[9].x**2)*partRatio**2+self.icoPts[9].z*self.icoPts[10].z-self.icoPts[9].z**2)/\ + ((self.icoPts[10].z**2-2*self.icoPts[9].z*self.icoPts[10].z+self.icoPts[10].y**2-\ + 2*self.icoPts[9].y*self.icoPts[10].y+self.icoPts[10].x**2-2*self.icoPts[9].x*\ + self.icoPts[10].x+self.icoPts[9].z**2+self.icoPts[9].y**2+self.icoPts[9].x**2)*\ + partRatio**2-self.icoPts[10].z**2+2*self.icoPts[9].z*self.icoPts[10].z-self.icoPts[9].z**2) + # print "lambda: ", lamb + testPartition = self.icoPts[9] +(self.icoPts[10] - self.icoPts[9]).multiply(lamb) + testPt = testPartition.normalize().multiply(self.domeRad) + #print "centerKruschke.z: ", centerKruschke.z, " testPt.z: ", testPt.z + + # see formula Kruschke_partition for further developing + # lambda=(ptz-p1z)/(p2z-p1z) + lamb2 = (centerIncircle.z - self.icoPts[10].z) \ + /(self.icoPts[9].z - self.icoPts[10].z) + #print "lambda2: ", lamb2 + + self.freq3Dict = {} # Dictionary for the frequency 3 partitioning + # Key = (growVecIdx, crossVecIdx) used in makeFreqFaces with + # indices k and l + # Contains the partition-values for growVec and crossVec + self.freq3Dict[(0,0)] = (0.0,0.0) # Point 10 + self.freq3Dict[(1,0)] = (lamb,0.0) # Point e + self.freq3Dict[(1,1)] = (lamb,lamb) # Point f + self.freq3Dict[(2,0)] = (1.0-lamb,0.0) # Point c + self.freq3Dict[(2,1)] = (2.0/3.0,1.0/3.0) # Point C + self.freq3Dict[(2,2)] = (1.0-lamb,1.0-lamb) # Point d + self.freq3Dict[(3,0)] = (1.0,0.0) # Point 9 + self.freq3Dict[(3,1)] = (1.0,lamb) # Point a + self.freq3Dict[(3,2)] = (1.0,1.0-lamb) # Point b + self.freq3Dict[(3,3)] = (1.0,1.0) # Point 1 + + + # lambda is the partitioning ratio for the points: a, b, c, d, e, f + # 1, 9, 10 are the indices of the icoPts + # C is the center-point of the icosahedron-triangle + # 10 + # /\ + # e-f + # /\ /\ + # c-C -d + # / \/\ /\ + # 9--a--b--1 + + + + + self.doc = App.newDocument("Geodesic_Dome") + #App.setActiveDocument(self.doc) + + #self.doc=App.activeDocument() + + self.doShell = True + self.doFlat = False + self.doFrame = False + self.doStrut = False + self.doBom = False + self.uFoStruts = [] # contains the unfolded struts + self.unFoldedFaces = [] + self.dFlatObject = None # contains later the flattened shell segment + self.flatFrame = None # doc object of Compound of flattened struts + self.bomCounts = Counter() # counts the struts of the different types + self.strutNames = dict() + self.nameIdx = 1 # counts the types of struts for naming the struts + self.strutDir = None # Direction of strut projection in strut drawing + + + + + def updateBomCounts(self, a, b, c): + ''' calls the counter for each strut of the dome''' + myTup = self.makeStrutKey(a, b, c) + #print "myTup: ", myTup + self.bomCounts[myTup] += 1 + + if not (myTup in self.strutNames): + firstIdx = 0 + secIdx = 0 + if self.nameIdx > 26: + firstIdx = int(self.nameIdx / 26) + secIdx = self.nameIdx - firstIdx*26 + if secIdx == 0: + secIdx = 26 + sName = chr(firstIdx + 64) + chr(secIdx + 64) + else: + sName = chr(self.nameIdx + 64) + self.strutNames[myTup] = sName + self.nameIdx += 1 + print ("add Name: ", sName, ' secIdx: ', secIdx, ' firstIdx: ', firstIdx) + + def makeStrutKey(self, a, b, c): + myKey = (round(a,6), round(b,6), round(c,6)) + return myKey + + + + def makeDome(self): + + thirdPt = self.icoPts[9] + for i in range(5): + #for i in range(1): + j = i*2+1 + self.makeFreqFaces(self.icoPts[0], thirdPt, self.icoPts[j], self.cutTop) + thirdPt = self.icoPts[j] + + thirdPt = self.icoPts[9] + secPt = self.icoPts[10] + for i in range(10): + j = i+1 + if i%2 == 0: + self.makeFreqFaces(secPt, self.icoPts[j], thirdPt, -self.cutMid) + else: + self.makeFreqFaces(secPt, thirdPt, self.icoPts[j], self.cutMid) + thirdPt = secPt + secPt = self.icoPts[j] + + thirdPt = self.icoPts[10] + for i in range(5): + j = i*2+2 + self.makeFreqFaces(self.icoPts[11], self.icoPts[j], thirdPt, -self.cutBottom) + thirdPt = self.icoPts[j] + + # Shell of the geodesic dome + #domeShell = Part.Shell(self.domeFaces) + # Part.show(domeShell) + + + def showDomeShell(self): + label = "GeodesicDomeShell" + self.dObject = self.doc.addObject("Part::Feature",label) + self.dObject.Shape = Part.Shell(self.domeFaces) + # self.doc.recompute() + print ("dome real data triangles: ", len(self.domeFaces)) + print ("dome real data vertexes: ", len(self.dObject.Shape.Vertexes)) + print ("dome real data edges: ", len(self.dObject.Shape.Edges)) + + def showDomeFrame(self): + frameGroup = self.doc.addObject("App::DocumentObjectGroup","DomeFrame") + strutGroups = dict() + for strut in self.domeStruts: + if not (strut.sName in strutGroups): + strutGroups[strut.sName] = self.doc.addObject \ + ("App::DocumentObjectGroup", strut.sName) + frameGroup.addObject(strutGroups[strut.sName]) + + strutI = App.ActiveDocument.addObject("Part::Feature","Strut_"+strut.sName+"_") + strutI.Shape = strut.Shape + strutGroups[strut.sName].addObject(strutI) + print ("dome real data struts: ", len(self.domeStruts)) + + def showFlatSegment(self): + print ("Flat called!" ) + fAx = self.icoPts[9] - self.icoPts[1] + fAn = DraftVecUtils.angle(Base.Vector(0.0, 0.0, 1.0), self.nodeDict[(0,0)].axis, fAx) + + if self.doShell: + print ("Flat shell now") + for rFace in self.unFoldedFaces: + rFace.rotate(Base.Vector(0.0, 0.0, self.domeRad),fAx,math.degrees(-fAn)) + #Part.show(rFace) + label = "FlatDomeShell" + self.dFlatObject = self.doc.addObject("Part::Feature",label) + self.dFlatObject.Shape = Part.Shell(self.unFoldedFaces) + + if self.doFrame: + print ("Flat Frame now") + #flatGroup = self.doc.addObject("App::DocumentObjectGroup","FlatDomeFrame") + for rStrut in self.uFoStruts: + rStrut.Shape.rotate(Base.Vector(0.0, 0.0, self.domeRad),fAx,math.degrees(-fAn)) + rStrut.annoPt.rotate(Base.Vector(0.0, 0.0, self.domeRad),fAx,math.degrees(-fAn)) + #strutI = self.doc.addObject("Part::Feature","FlatStrut") + #strutI.Shape = rStrut.Shape + #flatGroup.addObject(strutI) + + #Part.show(rStrut) + #Part.show(rStrut.annoPt) + strutShapes = [] + for i in self.uFoStruts: + strutShapes.append(i.Shape) + uFoStrutComp = Part.makeCompound(strutShapes) + self.flatFrame = self.doc.addObject("Part::Feature","FlatFrame") + self.flatFrame.Shape = uFoStrutComp + + #newShell = Part.Shell(unFoldedFaces) + #Part.show(newShell) + + + + def makeFreqFaces(self, fPt, sPt, thPt, cutIdx = None, band = None): + # band <> None: The nodeDict will be filled, in order to unfold + # the structure later. + # definition of direction vectors + # growVec goes from Vertex3 to Vertex2 with index k + growVec = (sPt - fPt) + # crossVec goes from Vertex2 to Vertex1 with index l + crossVec = (thPt - sPt) + if self.ny != 3: + growVec.multiply(1.0/self.ny) + crossVec.multiply(1.0/self.ny) + + # Indexing of triangle vertexes in the loop + # 4--3 + # \ | \ + # \ | \ + # 2--1 + # + # The Vertex4 is not used at index l==0 + # firstEdge 1_3 + # secEdge 2_1 + # thirdEdge 2_3 + # fourthEdge 3_4 + # fifthEdge 4_2 + + if cutIdx == None: + cutIdx = self.ny + startK = 0 + endK = cutIdx + if band != None: + bandForm = band # The band formula-value for calc purposes + kForm = 1 + if cutIdx < 0: + startK = self.ny + cutIdx + endK = self.ny + if band != None: + bandForm = band + self.ny -1 + kForm = -1 + + for k in range(startK, endK): + if self.ny != 3: + kThirdPt = fPt + growVec * (k+0.0) + kSecPt = fPt + growVec * (k+1.0) + else: + kThirdPt = fPt + growVec * self.freq3Dict[(k,0)][0] + kSecPt = fPt + growVec * self.freq3Dict[(k+1,0)][0] + + for l in range(k+1): + if band != None: + numberForm = 0 + if band == self.ny: + numberForm = (2*self.ny) - (2*k +1) + lForm = 2 + lOff = -1 + if cutIdx < 0: + numberForm = 2*k + lForm = -2 + lOff = 1 + + if self.ny != 3: + firstPt = kSecPt + crossVec *(l+1.0) + secPt = kSecPt + crossVec *(l+0.0) + thirdPt = kThirdPt + crossVec *(l+0.0) + else: + firstPt = fPt + growVec * self.freq3Dict[(k+1,l+1)][0] + crossVec * self.freq3Dict[(k+1,l+1)][1] + secPt = fPt + growVec * self.freq3Dict[(k+1,l)][0] + crossVec *self.freq3Dict[(k+1,l)][1] + thirdPt = fPt + growVec * self.freq3Dict[(k,l)][0] + crossVec *self.freq3Dict[(k,l)][1] + + dSecPt =secPt.normalize().multiply(self.domeRad) + dFirstPt = firstPt.normalize().multiply(self.domeRad) + dThirdPt = thirdPt.normalize().multiply(self.domeRad) + thirdEdge = Part.makeLine(dSecPt, dThirdPt) + # Part.show(thirdEdge) + + if l > 0: + fourthEdge = Part.makeLine(dThirdPt,dFourthPt) + triWire = Part.Wire([thirdEdge, fourthEdge, fifthEdge]) + # Part.show(triWire) + triFace = Part.Face(triWire) + if band is None: + self.domeFaces.append(triFace) + #Part.show(triFace) + triNorm = (dSecPt - dThirdPt).cross(dFourthPt - dThirdPt) + triNorm.normalize().multiply(self.domeRad/2.0) + #Normtest = Part.makeLine(dThirdPt, dThirdPt + triNorm) + #Part.show(Normtest) + + # angles of the triangle face + fourthGamma = self.getPtsAngle(dThirdPt, dFourthPt, dSecPt) / 2.0 + secGamma = self.getPtsAngle(dFourthPt, dSecPt, dThirdPt) / 2.0 + thirdGamma = self.getPtsAngle(dSecPt, dThirdPt, dFourthPt) / 2.0 + #print "Sum of angles: ", math.degrees(fourthGamma + secGamma + thirdGamma) + + # center of incircle + sumOfLength = thirdEdge.Length + fourthEdge.Length + fifthEdge.Length + cIdSecPt = Base.Vector(dSecPt.x, dSecPt.y, dSecPt.z) + cIdThirdPt = Base.Vector(dThirdPt.x, dThirdPt.y, dThirdPt.z) + cIdFourthPt = Base.Vector(dFourthPt.x, dFourthPt.y, dFourthPt.z) + centerIncircle = cIdSecPt.multiply(fourthEdge.Length / sumOfLength) \ + + cIdThirdPt.multiply(fifthEdge.Length / sumOfLength) \ + + cIdFourthPt.multiply(thirdEdge.Length / sumOfLength) + + + if band != None: + nodeBand = bandForm + k * kForm + nodeNumber = numberForm + lForm*l + lOff + self.nodeDict[(nodeBand, nodeNumber)] = Drawing_node(triFace.copy(), triNorm) + #Part.show(triFace) + #print "i,j: ",nodeBand, " ", nodeNumber + dMode = True # make struts for the drawing + + strut1 = self.makePriStrut(fifthEdge, \ + triNorm, fourthGamma, secGamma, False, dMode, centerIncircle) + strut2 = self.makePriStrut(fourthEdge, \ + triNorm, thirdGamma, fourthGamma, True, dMode, centerIncircle) + strut3 = self.makePriStrut(thirdEdge, \ + triNorm, secGamma, thirdGamma, True, dMode, centerIncircle) + self.nodeDict[(nodeBand, nodeNumber)].strutList.append(strut1) + self.nodeDict[(nodeBand, nodeNumber)].strutList.append(strut2) + self.nodeDict[(nodeBand, nodeNumber)].strutList.append(strut3) + else: + dMode = False # make struts for the 3D-frame + self.updateBomCounts(fifthEdge.Length, fourthGamma, secGamma) + strut1 = self.makePriStrut(fifthEdge, \ + triNorm, fourthGamma, secGamma, False, dMode, centerIncircle) + self.updateBomCounts(fourthEdge.Length, thirdGamma, fourthGamma) + strut2 = self.makePriStrut(fourthEdge, \ + triNorm, thirdGamma, fourthGamma, True, dMode, centerIncircle) + self.updateBomCounts(thirdEdge.Length, secGamma, thirdGamma) + strut3 = self.makePriStrut(thirdEdge, \ + triNorm, secGamma, thirdGamma, True, dMode, centerIncircle) + self.domeStruts.append(strut1) + self.domeStruts.append(strut2) + self.domeStruts.append(strut3) + #Part.show(strut1) + #Part.show(strut2) + #Part.show(strut3) + + + dFourthPt = dThirdPt + doFirstPt = dFirstPt + firstEdge = Part.makeLine(dFirstPt, dThirdPt) + fifthEdge = firstEdge + secEdge = Part.makeLine(dSecPt, dFirstPt) + triWire = Part.Wire([firstEdge, secEdge, thirdEdge]) + triFace = Part.Face(triWire) + if band is None: + self.domeFaces.append(triFace) + #Part.show(triFace) + + triNorm = (dSecPt - dFirstPt).cross(dThirdPt - dFirstPt) + triNorm.normalize().multiply(self.domeRad/3.0) + #Normtest = Part.makeLine(dFirstPt, dFirstPt + triNorm) + #Part.show(Normtest) + + # angles of the triangle face + firstGamma = self.getPtsAngle(dThirdPt, dFirstPt, dSecPt) / 2.0 + #print "FirstGamma: ", math.degrees(firstGamma) + secGamma = self.getPtsAngle(dFirstPt, dSecPt, dThirdPt) / 2.0 + thirdGamma = self.getPtsAngle(dSecPt, dThirdPt, dFirstPt) / 2.0 + + # center of incircle + sumOfLength = firstEdge.Length + secEdge.Length + thirdEdge.Length + cIdSecPt = Base.Vector(dSecPt.x, dSecPt.y, dSecPt.z) + cIdThirdPt = Base.Vector(dThirdPt.x, dThirdPt.y, dThirdPt.z) + cIdFirstPt = Base.Vector(dFirstPt.x, dFirstPt.y, dFirstPt.z) + centerIncircle = cIdSecPt.multiply(firstEdge.Length / sumOfLength) \ + + cIdThirdPt.multiply(secEdge.Length / sumOfLength) \ + + cIdFirstPt.multiply(thirdEdge.Length / sumOfLength) + #print 'centerIC: ', centerIncircle, ' sumL: ', sumOfLength + + if band != None: + #Part.show(Part.Vertex(centerIncircle.x, centerIncircle.y, centerIncircle.z)) + nodeBand = bandForm + k * kForm + #nodeNumber = 2*l + nodeNumber = numberForm + lForm*l + self.nodeDict[(nodeBand, nodeNumber)] = Drawing_node(triFace.copy(), triNorm) + #Part.show(triFace) + #print "i,j: ",nodeBand, " ", nodeNumber + dMode = True # make struts for the drawing + strut1 = self.makePriStrut(firstEdge, \ + triNorm, firstGamma, thirdGamma, True, dMode, centerIncircle) + strut2 = self.makePriStrut(secEdge, \ + triNorm, secGamma, firstGamma, True, dMode, centerIncircle) + strut3 = self.makePriStrut(thirdEdge, \ + triNorm, thirdGamma, secGamma, False, dMode, centerIncircle) + self.nodeDict[(nodeBand, nodeNumber)].strutList.append(strut1) + self.nodeDict[(nodeBand, nodeNumber)].strutList.append(strut2) + self.nodeDict[(nodeBand, nodeNumber)].strutList.append(strut3) + else: + dMode = False # make struts for the 3D-frame + self.updateBomCounts(firstEdge.Length, firstGamma, thirdGamma) + strut1 = self.makePriStrut(firstEdge, \ + triNorm, firstGamma, thirdGamma, True, dMode, centerIncircle) + self.updateBomCounts(secEdge.Length, secGamma, firstGamma) + strut2 = self.makePriStrut(secEdge, \ + triNorm, secGamma, firstGamma, True, dMode, centerIncircle) + self.updateBomCounts(thirdEdge.Length, thirdGamma, secGamma) + strut3 = self.makePriStrut(thirdEdge, \ + triNorm, thirdGamma, secGamma, False, dMode, centerIncircle) + self.domeStruts.append(strut1) + self.domeStruts.append(strut2) + self.domeStruts.append(strut3) + #Part.show(strut1) + #Part.show(strut2) + #Part.show(strut3) + + + def makePriStrut(self, theEdge, Norm, Gam0, Gam1, NormDir, \ + dMod=False, cIC = None): + ''' This function generates a strut for the dome frame. + - dMod stands for drawing mode = generating a flat segment + - Norm is the face normal of the corresponding dome triangle + - Normdir is the direction of the Edge, needed to make the strut + faces at the inner side of the dome triangle + - cIC is the center of the inner circle of the triangle + where this strut belongs to. It is used to calculate a point + to add an annotation in a drawing + ''' + + h = self.strutH + w = self.strutW + eLength = theEdge.Length + # Normalvectors of struts outer plane + theNorm = theEdge.valueAt(eLength/2.0) + theNorm.normalize().multiply(h) + + # angles between strut normal and face normal + alpha = theNorm.getAngle(Norm) + # print "alpha: ", math.degrees(alpha) + + # crossing point of the strut edges + # distance in triangle plane normal to theEdge + W1 = w / 2.0 * math.cos(alpha) + #print "firstW1: ", W1 + if W1 < 0.0: + W1 = -W1 + + if NormDir: + theStart = theEdge.valueAt(0.0) + theEnd = theEdge.valueAt(eLength) + startVal = 0.0 + endVal = theEdge.Length + else: + theStart = theEdge.valueAt(eLength) + theEnd = theEdge.valueAt(0.0) + startVal = eLength + endVal = 0.0 + theVec0 = theEnd - theStart + theVec1 = theEnd - theStart + vec2 = theEnd - theStart # needed for annotation point + theCross = theNorm.cross(theVec0) + theCross.normalize().multiply(w/2.0) + + beta = (math.pi - theEnd.getAngle(theStart)) / 2.0 + sinBeta = math.sin(beta) + # variables with big S at the end are the values for the + # Smaller inner points of the dome frame + domeRadS = self.domeRad - h / sinBeta + theStartS = Base.Vector(theStart.x, theStart.y, theStart.z) + theStartS = theStartS.normalize().multiply(domeRadS) + theEndS = Base.Vector(theEnd.x, theEnd.y, theEnd.z) + theEndS = theEndS.normalize().multiply(domeRadS) + + off0 = W1 / math.tan(Gam0) + theVec0.normalize().multiply(off0) + off1 = W1 / math.tan(Gam1) + theVec1.normalize().multiply(off1) + + # Printing BOM-data to the console + #print eLength, ",", math.degrees(beta), ",", \ + # math.degrees(Gam0), ",", math.degrees(Gam1) + + + # Testpoints + #tLine = Part.makeLine(theEdge.valueAt(off0), theEdge.valueAt(off0) - theCross) + #Part.show(tLine) + theStrutFaces = [] + + pt0 = theStart + theVec0 - theCross + pt1 = theEnd - theVec1 - theCross + pt0S = theStartS + theVec0 - theCross + pt1S = theEndS - theVec1 - theCross + + inEd1 = Part.makeLine(pt0, pt1) + inEd2 = Part.makeLine(pt1, pt1S) + inEd3 = Part.makeLine(pt1S, pt0S) + inEd4 = Part.makeLine(pt0S, pt0) + inEd4rev = Part.makeLine(pt0, pt0S) + + strW1 = Part.Wire([inEd1, inEd2, inEd3, inEd4]) + strF1 = Part.Face(strW1) + # Part.show(strF1) + theStrutFaces.append(strF1) + + outEd1 = Part.makeLine(theStart, theEnd) + outEd2 = Part.makeLine(theEnd, theEndS) + outEd3 = Part.makeLine(theEndS, theStartS) + outEd4 = Part.makeLine(theStartS, theStart) + + strW2 = Part.Wire([outEd1, outEd2, outEd3, outEd4]) + strF2 = Part.Face(strW2) + # Part.show(strF2) + theStrutFaces.append(strF2) + + c0Ed1 = Part.makeLine(theStart, pt0) + c0Ed2 = Part.makeLine(pt0S, theStartS) + c1Ed1 = Part.makeLine(theEnd, pt1) + c1Ed2 = Part.makeLine(pt1S, theEndS) + + strW3 = Part.Wire([c0Ed1, inEd4rev, c0Ed2, outEd4]) + #strW3.fixWire() + #strW3.isClosed() + #print "Wire3: ", strW3.isClosed() + #Part.show(strW3) + strF3 = Part.Face(strW3) + #Part.show(strF3) + theStrutFaces.append(strF3) + + strW4 = Part.Wire([c1Ed1, inEd2, c1Ed2, outEd2]) + #Part.show(strW4) + strF4 = Part.Face(strW4) + # Part.show(strF4) + theStrutFaces.append(strF4) + + strW5 = Part.Wire([outEd1, c1Ed1, inEd1, c0Ed1]) + #Part.show(strW5) + strF5 = Part.Face(strW5) + # Part.show(strF5) + theStrutFaces.append(strF5) + + strW6 = Part.Wire([outEd3, c1Ed2, inEd3, c0Ed2]) + strF6 = Part.Face(strW6) + # Part.show(strF6) + theStrutFaces.append(strF6) + + strShell = Part.makeShell(theStrutFaces) + + strutName = self.strutNames[self.makeStrutKey(eLength, Gam0, Gam1)] + + # calculation of the annotation point + #vec2 = theEnd - theStart + + lam = (vec2.z*cIC.z+vec2.y*cIC.y+vec2.x*cIC.x-theStart.z*vec2.z \ + -theStart.y*vec2.y-theStart.x*vec2.x)/(vec2.z**2+vec2.y**2+vec2.x**2) + + # tPt touch-point at strut length + tPt = theStart + vec2.multiply(lam) + annoDistFact = (w/2.0 + ((cIC - tPt).Length-w/2.0)/3.0) / (cIC - tPt).Length + + annoPt = tPt + (cIC - tPt).multiply(annoDistFact) + annoVert = Part.Vertex(annoPt.x, annoPt.y, annoPt.z) + + strut = Strut(Part.makeSolid(strShell), strutName, annoVert, \ + theNorm.normalize()) + if dMod: + #rFace.rotate(fPt,fAx,math.degrees(-fAn)) + strut.Shape.rotate(theStart, theVec0, math.degrees(alpha)) + #testline = Part.makeLine(cIC, annoPt) + #Part.show(testline) + # Part.show(strut) + return strut + + + def getPtsAngle(self, pt1, pt2, pt3): + #return the angle at pt2 + vec1 = pt1 - pt2 + vec2 = pt3 - pt2 + return vec1.getAngle(vec2) + + + def equalEdge(self, ed1, ed2, p=6): + # compares two edges + e1v1 = ed1.Vertex1 + e1v2 = ed1.Vertex2 + e2v1 = ed2.Vertex1 + e2v2 = ed2.Vertex2 + + comp1 = (round(e1v1.X - e2v1.X,p)==0 and \ + round(e1v1.Y - e2v1.Y,p)==0 and round(e1v1.Z - e2v1.Z,p)==0) + comp2 = (round(e1v1.X - e2v2.X,p)==0 and \ + round(e1v1.Y - e2v2.Y,p)==0 and round(e1v1.Z - e2v2.Z,p)==0) + comp3 = (round(e1v2.X - e2v1.X,p)==0 and \ + round(e1v2.Y - e2v1.Y,p)==0 and round(e1v2.Z - e2v1.Z,p)==0) + comp4 = (round(e1v2.X - e2v2.X,p)==0 and \ + round(e1v2.Y - e2v2.Y,p)==0 and round(e1v2.Z - e2v2.Z,p)==0) + + return ((comp1 or comp2) and (comp3 or comp4)) + + def searchFoldData(self, pFace, cFace): + rEdge = None + for pEdge in pFace.Edges: + # print 'P: ', pEdge.Vertexes[0].Point, ' ', pEdge.Vertexes[1].Point + for cEdge in cFace.Edges: + # print 'C: ', cEdge.Vertexes[0].Point, ' ', cEdge.Vertexes[1].Point + #if cEdge.isSame(pEdge): # Does not work for what ever reason!? + if self.equalEdge(cEdge, pEdge): + rEdge = cEdge + break + if rEdge == None: + print ("Error: no common Edge found!") + #Part.show(pFace) + #Part.show(cFace) + #else: + # Part.show(cFace) + fAxis = rEdge.Vertexes[1].Point - rEdge.Vertexes[0].Point + return fAxis, rEdge.Vertexes[0].Point + + + def unfold_tree(self, node): + # This function traverses the tree and unfolds the faces + # beginning at the outermost nodes. + # print "unfold_tree face", node.idx + 1 + theShell = [] + theStruts = [] + for nodeKey in node.children: + moreFaces, moreStruts = self.unfold_tree(self.nodeDict[nodeKey]) + theShell = theShell + moreFaces + theStruts = theStruts + moreStruts + # nodeShell = [node.triFace] # self.generateBendShell(node) + theShell.append(node.triFace) + theStruts = theStruts + node.strutList + + if node.parent != None: + fAx, fPt = self.searchFoldData(self.nodeDict[node.parent].triFace, node.triFace) + fAn = DraftVecUtils.angle(self.nodeDict[node.parent].axis, node.axis, fAx) + #fAn = nodeDict[node.parent].axis.getAngle(node.axis) + #print "FoldData Angle: ", math.degrees(fAn) + + for rFace in theShell: + rFace.rotate(fPt,fAx,math.degrees(-fAn)) + for rStrut in theStruts: + rStrut.Shape.rotate(fPt,fAx,math.degrees(-fAn)) + rStrut.annoPt.rotate(fPt,fAx,math.degrees(-fAn)) + + #return (theShell + nodeShell) + return theShell, theStruts + + def makeNodes(self): + # make a segment for a drawing + thirdPt = self.icoPts[9] + for i in range(1): + j = i*2+1 + self.makeFreqFaces(self.icoPts[0], thirdPt, self.icoPts[j], self.cutTop, 0) + thirdPt = self.icoPts[j] + + thirdPt = self.icoPts[9] + secPt = self.icoPts[10] + + for i in range(2): + j = i+1 + if i%2 == 0: + self.makeFreqFaces(secPt, self.icoPts[j], thirdPt, -self.cutMid, self.ny) + else: + self.makeFreqFaces(secPt, thirdPt, self.icoPts[j], self.cutMid, self.ny) + + thirdPt = secPt + secPt = self.icoPts[j] + + thirdPt = self.icoPts[10] + for i in range(1): + j = i*2+2 + self.makeFreqFaces(self.icoPts[11], self.icoPts[j], thirdPt, -self.cutBottom, 2*self.ny) + thirdPt = self.icoPts[j] + + + # Shell of the geodesic segment + #domeShell = Part.Shell(domeFaces) + #Part.show(domeShell) + + # make the parent-child relation + if self.ny > 1: + self.nodeDict[(0,0)].children = [(1,1)] + self.nodeDict[(1,1)].parent = (0,0) + else: + if self.totalBands > 1: + self.nodeDict[(0,0)].children = [(1,0)] + self.nodeDict[(1,0)].parent = (0,0) + + + for i in range(1,self.cutTop): + #print "Adoption 1 start: ", i + if i==(self.ny-1): + child = 0 + else: + child = 1 + if (i< self.totalBands-1): + self.nodeDict[(i,0)].children.append((i+1,child)) + self.nodeDict[(i+1,child)].parent = (i,0) + #Part.show(self.nodeDict[(i,j)].triFace) + if i>0: + self.nodeDict[(i,1)].children.append((i,0)) + self.nodeDict[(i,0)].parent = (i,1) + for j in range(1,2*i): + #print "Adoption 1 i: ",i ," j: ",j + self.nodeDict[(i,j)].children.append((i,j+1)) + self.nodeDict[(i,j+1)].parent = (i,j) + #Part.show(self.nodeDict[(i,j)].triFace) + + for i in range(self.ny, self.ny + self.cutMid): + for j in range(2*self.ny): + #print "Adoption 2 i: ",i ," j: ",j + if (j == 1) and (i< self.totalBands-1): + self.nodeDict[(i,j)].children.append((i+1,0)) + self.nodeDict[(i+1,0)].parent = (i,j) + if (j<(2*self.ny-1)): + self.nodeDict[(i,j)].children.append((i,j+1)) + self.nodeDict[(i,j+1)].parent = (i,j) + #Part.show(self.nodeDict[(i,j)].triFace) + + jMax = 2*self.ny -2 + for i in range(2*self.ny, 2*self.ny + self.cutBottom ): + for j in range(jMax): + #print "Adoption 3 i: ",i ," j: ",j + if (j == 1) and (i< self.totalBands-1): + self.nodeDict[(i,j)].children.append((i+1,0)) + self.nodeDict[(i+1,0)].parent = (i,j) + self.nodeDict[(i,j)].children.append((i,j+1)) + self.nodeDict[(i,j+1)].parent = (i,j) + #Part.show(self.nodeDict[(i,j)].triFace) + jMax = jMax - 2 + + self.unFoldedFaces, self.uFoStruts = self.unfold_tree(self.nodeDict[(0,0)]) + + + + +d = QtGui.QWidget() +d.ui = Ui_Dialog() +d.ui.setupUi(d) +d.ui.updateInfo() + +d.show() diff --git a/README.md b/README.md index 6d81249..fdcbc4d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,16 @@ # FreeCAD-Macros +Different macros to create geodesic domes with FreeCAD 20.2 + +## Sources + +# dome.py + - based on https://wiki.freecad.org/Macro_Geodesic_Dome + +# dome_advanced.py + - based on https://forum.freecad.org/viewtopic.php?p=125238#p125238 + - modified to work with FreeCAD 20.2 + - has some glitches at the moment: + - diameter is wrong + - spreadsheets cannot calculate all fields because some contain units with plain text +