Difference between revisions of "Macro Geodesic Dome"

From FreeCAD Documentation
Jump to navigation Jump to search
(upgrades: parametric, supports Py3)
(Undo revision 437745 by DeepSOIC (talk) (I realized, on github, the version is different! Thus needs revision.))
Line 15: Line 15:
 
<!--T:3-->
 
<!--T:3-->
 
[[File:Geodesic macro.png|600px]]
 
[[File:Geodesic macro.png|600px]]
 
==Installation==
 
 
Save the following script as MacroGeodesicDome.py to your macro directory.
 
  
 
==Script== <!--T:4-->
 
==Script== <!--T:4-->
 
</translate>
 
</translate>
  
'''MacroGeodesicDome.py'''
+
'''Macro_Geodesic_Dome.FCMacro'''
  
 
{{Code|code=
 
{{Code|code=
 
# -*- coding: utf-8 -*-
 
# -*- coding: utf-8 -*-
  
# ************************************************************************
+
# Form implementation generated from reading ui file 'geodesic_dialog.ui'
# * Copyright (c)2015 Ulrich Brammer <ulrich1a[at]users.sourceforge.net> *
+
# And changed manually to use FreeCAD "Gui::InputField"
# *                                                                      *
+
# Created: Sun Jan  4 22:20:58 2015
# * This file is a supplement to the FreeCAD CAx development system.    *
+
#      by: pyside-uic 0.2.15 running on PySide 1.2.2
# *                                                                      *
+
#
# * 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.                  *
+
* Copyright (c)2015 Ulrich Brammer <ulrich1a[at]users.sourceforge.net> *
# * for detail see the LICENCE text file.                                *
+
*                                                                      *
# *                                                                      *
+
* This file is a supplement to the FreeCAD CAx development system.    *
# * This software is distributed in the hope that it will be useful,    *
+
*                                                                      *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of      *
+
* This program is free software; you can redistribute it and/or modify *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
+
* it under the terms of the GNU Lesser General Public License (LGPL)  *
# * GNU Library General Public License for more details.                *
+
* as published by the Free Software Foundation; either version 2 of    *
# *                                                                      *
+
* the License, or (at your option) any later version.                  *
# * You should have received a copy of the GNU Library General Public    *
+
* for detail see the LICENCE text file.                                *
# * License along with this macro; if not, write to the Free Software    *
+
*                                                                      *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 *
+
* This software is distributed in the hope that it will be useful,    *
# * USA                                                                  *
+
* 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                                                                  *
 +
*                                                                      *
 +
************************************************************************
 +
'''
  
  
Line 56: Line 60:
 
from FreeCAD import Base
 
from FreeCAD import Base
  
def makeDomeShape(domeRad, ny):
+
class Ui_Dialog(object):
     #semi-global variables
+
  def setupUi(self, Dialog):
     a = 0 #Strutlength of underlying icosahedron:
+
     Dialog.setObjectName("Dialog")
     icoFaces = [] # collects faces of the underlying icosahedron
+
    Dialog.resize(477, 188)
     domeFaces = [] # collects the faces of the geodesic dome
+
    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):
 +
    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))
 +
 
 +
  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):
 
     def makeFreqFaces(fPt, sPt, thPt, ny = 1):
        # makes the geodesic dome faces out of the points of an
+
      # makes the geodesic dome faces out of the points of an
        # icosahedron triangle
+
      # icosahedron triangle
        b = a/ny # length of frequent triangles
+
      b = self.a/ny # length of frequent triangles
        # definition of direction vectors
+
      # definition of direction vectors
        growVec = (sPt - fPt)
+
      growVec = (sPt - fPt)
        # growVec = (fPt - sPt)
+
      # growVec = (fPt - sPt)
        growVec.multiply(1.0/ny)
+
      growVec.multiply(1.0/ny)
        crossVec = (thPt - sPt)
+
      crossVec = (thPt - sPt)
        # crossVec = (sPt - thPt)
+
      # crossVec = (sPt - thPt)
        crossVec.multiply(1.0/ny)
+
      crossVec.multiply(1.0/ny)
       
+
     
        for k in range(ny):
+
      for k in range(ny):
            kThirdPt = fPt + growVec * (k+0.0)
+
        kThirdPt = fPt + growVec * (k+0.0)
            dThirdPt = Base.Vector(kThirdPt.x, kThirdPt.y, kThirdPt.z)
+
        dThirdPt = Base.Vector(kThirdPt.x, kThirdPt.y, kThirdPt.z)
            dThirdPt = dThirdPt.normalize().multiply(domeRad)
+
        dThirdPt = dThirdPt.normalize().multiply(domeRad.Value)
            kSecPt = fPt + growVec * (k+1.0)
+
        kSecPt = fPt + growVec * (k+1.0)
            dSecPt = Base.Vector(kSecPt.x, kSecPt.y, kSecPt.z)
+
        dSecPt = Base.Vector(kSecPt.x, kSecPt.y, kSecPt.z)
            dSecPt = dSecPt.normalize().multiply(domeRad)
+
        dSecPt = dSecPt.normalize().multiply(domeRad.Value)
            # thirdEdge = Part.makeLine(kSecPt, kThirdPt)
+
        # thirdEdge = Part.makeLine(kSecPt, kThirdPt)
            # thirdEdge = Part.makeLine(dSecPt, dThirdPt)
+
        # thirdEdge = Part.makeLine(dSecPt, dThirdPt)
            for l in range(k+1):
+
        for l in range(k+1):
                firstPt = kSecPt + crossVec *(l+1.0)
+
          firstPt = kSecPt + crossVec *(l+1.0)
                dFirstPt = firstPt.normalize().multiply(domeRad)
+
          dFirstPt = firstPt.normalize().multiply(domeRad.Value)
                secPt = kSecPt + crossVec *(l+0.0)
+
          secPt = kSecPt + crossVec *(l+0.0)
                dSecPt =secPt.normalize().multiply(domeRad)
+
          dSecPt =secPt.normalize().multiply(domeRad.Value)
                thirdPt = kThirdPt + crossVec *(l+0.0)
+
          thirdPt = kThirdPt + crossVec *(l+0.0)
                dThirdPt = thirdPt.normalize().multiply(domeRad)
+
          dThirdPt = thirdPt.normalize().multiply(domeRad.Value)
                #thirdEdge = Part.makeLine(secPt, thirdPt)
+
          #thirdEdge = Part.makeLine(secPt, thirdPt)
                thirdEdge = Part.makeLine(dSecPt, dThirdPt)
+
          thirdEdge = Part.makeLine(dSecPt, dThirdPt)
                # Part.show(thirdEdge)
+
          # Part.show(thirdEdge)
                if l > 0:
+
          if l > 0:
                    print("in l: ", l, " mod 2: ", l%2)
+
            print "in l: ", l, " mod 2: ", l%2
                    # What to do here?
+
            # What to do here?
                    #secEdge = Part.makeLine(oThirdPt,thirdPt)
+
            #secEdge = Part.makeLine(oThirdPt,thirdPt)
                    secEdge = Part.makeLine(doThirdPt,dThirdPt)
+
            secEdge = Part.makeLine(doThirdPt,dThirdPt)
                    # Part.show(secEdge)
+
            # Part.show(secEdge)
                    #thirdEdge = Part.makeLine(secPt, thirdPt)
+
            #thirdEdge = Part.makeLine(secPt, thirdPt)
                    #thirdEdge = Part.makeLine(dSecPt, dThirdPt)
+
            #thirdEdge = Part.makeLine(dSecPt, dThirdPt)
                    # Part.show(thirdEdge)
+
            # Part.show(thirdEdge)
                    triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
+
            triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
                    # Part.show(triWire)
+
            # Part.show(triWire)
                    triFace = Part.Face(triWire)
+
            triFace = Part.Face(triWire)
                    domeFaces.append(triFace)
+
            self.domeFaces.append(triFace)
                    #Part.show(triFace)
+
            #Part.show(triFace)
               
+
         
                oThirdPt = thirdPt
+
          oThirdPt = thirdPt
                doThirdPt = oThirdPt.normalize().multiply(domeRad)
+
          doThirdPt = oThirdPt.normalize().multiply(domeRad.Value)
                # oFirstPt = firstPt
+
          # oFirstPt = firstPt
                #firstEdge = Part.makeLine(thirdPt,firstPt)
+
          #firstEdge = Part.makeLine(thirdPt,firstPt)
                firstEdge = Part.makeLine(dThirdPt,dFirstPt)
+
          firstEdge = Part.makeLine(dThirdPt,dFirstPt)
                oFirstEdge = firstEdge
+
          oFirstEdge = firstEdge
                #secEdge = Part.makeLine(firstPt,secPt)
+
          #secEdge = Part.makeLine(firstPt,secPt)
                secEdge = Part.makeLine(dFirstPt,dSecPt)
+
          secEdge = Part.makeLine(dFirstPt,dSecPt)
                #Part.show(firstEdge)
+
          #Part.show(firstEdge)
                #Part.show(secEdge)
+
          #Part.show(secEdge)
                #Part.show(thirdEdge)
+
          #Part.show(thirdEdge)
                triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
+
          triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
                triFace = Part.Face(triWire)
+
          triFace = Part.Face(triWire)
                domeFaces.append(triFace)
+
          self.domeFaces.append(triFace)
                #Part.show(triFace)
+
          #Part.show(triFace)
 +
   
 
      
 
      
       
+
    domeRad = FreeCAD.Units.Quantity(domeRad_str)
     a=(4.0*domeRad)/math.sqrt(2.0*math.sqrt(5.0)+10.0)  
+
 
 +
     # 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  
 
     # icoAngle: angle of vertices of icosahedron points  
 
     # not a north or south pole
 
     # not a north or south pole
     icoAngle = math.atan(0.5)
+
     self.icoAngle = math.atan(0.5)
 
      
 
      
     icoLat = domeRad * math.sin(icoAngle)
+
     self.icoLat = domeRad.Value * math.sin(self.icoAngle)
     latRad = domeRad * math.cos(icoAngle)
+
     self.latRad = domeRad.Value * math.cos(self.icoAngle)
     ang36 = math.radians(36.0)
+
     self.ang36 = math.radians(36.0)
 
      
 
      
 
     # Calculation all points of the icosahedron
 
     # Calculation all points of the icosahedron
     icoPts = []
+
     self.icoPts = []
     icoPts.append(Base.Vector(0.0, 0.0, domeRad))
+
     self.icoPts.append(Base.Vector(0.0, 0.0, domeRad.Value))
 
      
 
      
 
     for i in range(10):
 
     for i in range(10):
        icoCos = latRad * math.cos(i*ang36)
+
      self.icoCos = self.latRad * math.cos(i*self.ang36)
        icoSin = latRad * math.sin(i*ang36)
+
      self.icoSin = self.latRad * math.sin(i*self.ang36)
        if i%2 == 0:
+
      if i%2 == 0:
            icoPts.append(Base.Vector(icoSin, icoCos, icoLat))
+
        self.icoPts.append(Base.Vector(self.icoSin, self.icoCos, self.icoLat))
        else:
+
      else:
            icoPts.append(Base.Vector(icoSin, icoCos, -icoLat))
+
        self.icoPts.append(Base.Vector(self.icoSin, self.icoCos, -self.icoLat))
 
      
 
      
     icoPts.append(Base.Vector(0.0, 0.0, -domeRad))
+
     self.icoPts.append(Base.Vector(0.0, 0.0, -domeRad.Value))
 
      
 
      
 
     # making the faces of the icosahedron
 
     # making the faces of the icosahedron
 
      
 
      
 +
    self.icoFaces = [] # collects faces of the underlying icosahedron
 +
    self.domeFaces = [] # collects the faces of the geodesic dome
 
      
 
      
     thirdPt = icoPts[9]
+
     thirdPt = self.icoPts[9]
     thirdEdge = Part.makeLine(icoPts[0],thirdPt)
+
     thirdEdge = Part.makeLine(self.icoPts[0],thirdPt)
 
     for i in range(5):
 
     for i in range(5):
        j = i*2+1
+
      j = i*2+1
        firstEdge = Part.makeLine(thirdPt,icoPts[j])
+
      firstEdge = Part.makeLine(thirdPt,self.icoPts[j])
        secEdge = Part.makeLine(icoPts[j],icoPts[0])
+
      secEdge = Part.makeLine(self.icoPts[j],self.icoPts[0])
        triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
+
      triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
        triFace = Part.Face(triWire)
+
      triFace = Part.Face(triWire)
        icoFaces.append(triFace)
+
      self.icoFaces.append(triFace)
        # Part.show(triFace)
+
      # Part.show(triFace)
        makeFreqFaces(icoPts[j], icoPts[0], thirdPt, ny)
+
      makeFreqFaces(self.icoPts[j], self.icoPts[0], thirdPt, ny)
       
+
     
        thirdEdge = Part.makeLine(icoPts[0],icoPts[j])
+
      thirdEdge = Part.makeLine(self.icoPts[0],self.icoPts[j])
        thirdPt = icoPts[j]
+
      thirdPt = self.icoPts[j]
       
+
     
     thirdPt = icoPts[9]
+
     thirdPt = self.icoPts[9]
     secPt = icoPts[10]
+
     secPt = self.icoPts[10]
 
     thirdEdge = Part.makeLine(secPt,thirdPt)
 
     thirdEdge = Part.makeLine(secPt,thirdPt)
 
      
 
      
 
     for i in range(10):
 
     for i in range(10):
        j = i+1
+
      j = i+1
        firstEdge = Part.makeLine(thirdPt,icoPts[j])
+
      firstEdge = Part.makeLine(thirdPt,self.icoPts[j])
        secEdge = Part.makeLine(icoPts[j],secPt)
+
      secEdge = Part.makeLine(self.icoPts[j],secPt)
        triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
+
      triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
        triFace = Part.Face(triWire)
+
      triFace = Part.Face(triWire)
        icoFaces.append(triFace)
+
      self.icoFaces.append(triFace)
        #Part.show(triFace)
+
      #Part.show(triFace)
        makeFreqFaces(icoPts[j], secPt, thirdPt, ny)
+
      makeFreqFaces(self.icoPts[j], secPt, thirdPt, ny)
 
      
 
      
        thirdPt = secPt
+
      thirdPt = secPt
        secPt = icoPts[j]
+
      secPt = self.icoPts[j]
        thirdEdge = Part.makeLine(secPt,thirdPt)
+
      thirdEdge = Part.makeLine(secPt,thirdPt)
 
      
 
      
 
      
 
      
     thirdPt = icoPts[10]
+
     thirdPt = self.icoPts[10]
     thirdEdge = Part.makeLine(icoPts[11],thirdPt)
+
     thirdEdge = Part.makeLine(self.icoPts[11],thirdPt)
 
     for i in range(5):
 
     for i in range(5):
        j = i*2+2
+
      j = i*2+2
        firstEdge = Part.makeLine(thirdPt,icoPts[j])
+
      firstEdge = Part.makeLine(thirdPt,self.icoPts[j])
        secEdge = Part.makeLine(icoPts[j],icoPts[11])
+
      secEdge = Part.makeLine(self.icoPts[j],self.icoPts[11])
        triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
+
      triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
        triFace = Part.Face(triWire)
+
      triFace = Part.Face(triWire)
        icoFaces.append(triFace)
+
      self.icoFaces.append(triFace)
        #Part.show(triFace)
+
      #Part.show(triFace)
        makeFreqFaces(icoPts[j], icoPts[11], thirdPt, ny)
+
      makeFreqFaces(self.icoPts[j], self.icoPts[11], thirdPt, ny)
       
+
     
        thirdEdge = Part.makeLine(icoPts[11],icoPts[j])
+
      thirdEdge = Part.makeLine(self.icoPts[11],self.icoPts[j])
        thirdPt = icoPts[j]
+
      thirdPt = self.icoPts[j]
 
      
 
      
     # Shell of a corresponding icosahedron
+
     # Shell of a corresponding icosahedron
     newShell = Part.Shell(icoFaces)
+
     newShell = Part.Shell(self.icoFaces)
 
     #Part.show(newShell)
 
     #Part.show(newShell)
 
      
 
      
 
     # Shell of the geodesic dome
 
     # Shell of the geodesic dome
     #domeShell = Part.Shell(domeFaces)
+
     #self.domeShell = Part.Shell(self.domeFaces)
     #Part.show(domeShell)
+
     #Part.show(self.domeShell)
     return Part.Shell(domeFaces)
+
     obj.Shape = Part.Shell(self.domeFaces)
 
      
 
      
 
     # Shere with radius of geodesic dome for debugging purposes
 
     # Shere with radius of geodesic dome for debugging purposes
     # testSphere = Part.makeSphere(domeRad)
+
     testSphere = Part.makeSphere(domeRad.Value)
 
     #Part.show(testSphere)
 
     #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")
  
class Ui_Dialog(object):
+
d.show()
    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)
 
 
 
        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")
 
       
 
        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 makeSomething(self):
 
        print("accepted! Dome radius: ", self.lineEdit.property("text"), \
 
              " with Frequency: ", int(self.lineEdit_2.text()))
 
       
 
        if FreeCAD.ActiveDocument is None:
 
            FreeCAD.newDocument()
 
        doc = FreeCAD.ActiveDocument
 
        theDome = GeodesicDome(doc).host
 
        theDome.Radius = FreeCAD.Units.Quantity(self.lineEdit.property("text"))
 
        theDome.FrequencyParameter = int(self.lineEdit_2.text())
 
           
 
        self.dia.close()
 
        doc.recompute()
 
       
 
    def makeNothing(self):
 
        print("rejected!!")
 
        self.dia.close()
 
 
 
def showDialog():
 
    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()
 
   
 
 
 
class GeodesicDome(object):
 
    host = None
 
    def __init__(self, doc):
 
        host = doc.addObject('Part::FeaturePython', 'GeoDome')
 
        self.host = host
 
        host.Proxy = self
 
       
 
        VPGeodesicDome(host.ViewObject)
 
       
 
        host.addProperty('App::PropertyLength', 'Radius', "Geodesic Dome", "")
 
        host.addProperty('App::PropertyInteger', 'FrequencyParameter', "Geodesic Dome", "Frequency Parameter (integer, 1 to 10). If even, the dome is symmetric against XY plane.")
 
        host.addProperty('App::PropertyEnumeration', 'ShapeType', "Geodesic Dome", "")
 
        host.ShapeType = ['Solid', 'Shell', 'Wireframe', 'Vertices']
 
   
 
    def execute(self, host):
 
        shell = makeDomeShape(host.Radius.getValueAs('mm'), host.FrequencyParameter)
 
        if host.ShapeType == 'Solid':
 
            host.Shape = Part.Solid(shell)
 
        elif host.ShapeType == 'Shell':
 
            host.Shape = shell
 
        elif host.ShapeType == 'Wireframe':
 
            host.Shape = Part.Compound(shell.Edges)
 
        elif host.ShapeType == 'Vertices':
 
            host.Shape = Part.Compound(shell.Vertexes)
 
        else:
 
            assert(False)
 
 
 
    def __getstate__(self):
 
        return None
 
 
 
    def __setstate__(self,state):
 
        return None
 
   
 
class VPGeodesicDome(object):
 
    def __init__(self, host):
 
        host.Proxy = self
 
   
 
    def __getstate__(self):
 
        return None
 
 
 
    def __setstate__(self,state):
 
        return None
 
 
 
if __name__ == '__main__':
 
    #running as a macro. Load as module, to support save-restore.
 
    try:
 
        import MacroGeodesicDome   
 
    except ImportError as err:
 
        FreeCAD.Console.PrintError("Macro Geodesic Dome: failed to import MacroGeodesicDome.py. The parametric object will lose functionality after saving-loading your project, sorry.")
 
        showDialog()
 
    else:
 
        MacroGeodesicDome.showDialog()
 
 
}}
 
}}
  

Revision as of 19:40, 8 March 2019

Other languages:
English • ‎français • ‎italiano

Macro Geodesic Dome.svg Macro Geodesic Dome

Description
This macro creates a geodesic dome

Macro version: 01.00
Last modified: 2015-01-04
Author
Ulrich Brammer
Download
None
Links
Macro Version
01.00
Date last modified
2015-01-04
FreeCAD Version(s)
None
Default shortcut
None
See also
None


Description

This macro creates a geodesic dome shell. The dome radius and the frequency parameter will be set at creation time.

Geodesic macro.png

Script

Macro_Geodesic_Dome.FCMacro

# -*- 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
#
# 
'''
************************************************************************
* Copyright (c)2015 Ulrich Brammer <ulrich1a[at]users.sourceforge.net> *
*                                                                      *
* 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):
    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))

  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()

Get the code from Github here!