Macro Geodesic Dome: Difference between revisions

From FreeCAD Documentation
(Vertical {{Macro}}; fixed icon)
(upgrades: parametric, supports Py3)
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>


'''Macro_Geodesic_Dome.FCMacro'''
'''MacroGeodesicDome.py'''


{{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 60: Line 56:
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 = self.a/ny # length of frequent triangles
b = 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.Value)
dThirdPt = dThirdPt.normalize().multiply(domeRad)
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.Value)
dSecPt = dSecPt.normalize().multiply(domeRad)
# 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.Value)
dFirstPt = firstPt.normalize().multiply(domeRad)
secPt = kSecPt + crossVec *(l+0.0)
secPt = kSecPt + crossVec *(l+0.0)
dSecPt =secPt.normalize().multiply(domeRad.Value)
dSecPt =secPt.normalize().multiply(domeRad)
thirdPt = kThirdPt + crossVec *(l+0.0)
thirdPt = kThirdPt + crossVec *(l+0.0)
dThirdPt = thirdPt.normalize().multiply(domeRad.Value)
dThirdPt = thirdPt.normalize().multiply(domeRad)
#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)
self.domeFaces.append(triFace)
domeFaces.append(triFace)
#Part.show(triFace)
#Part.show(triFace)
oThirdPt = thirdPt
oThirdPt = thirdPt
doThirdPt = oThirdPt.normalize().multiply(domeRad.Value)
doThirdPt = oThirdPt.normalize().multiply(domeRad)
# 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)
self.domeFaces.append(triFace)
domeFaces.append(triFace)
#Part.show(triFace)
#Part.show(triFace)
a=(4.0*domeRad)/math.sqrt(2.0*math.sqrt(5.0)+10.0)
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
# icoAngle: angle of vertices of icosahedron points
# not a north or south pole
# not a north or south pole
self.icoAngle = math.atan(0.5)
icoAngle = math.atan(0.5)
self.icoLat = domeRad.Value * math.sin(self.icoAngle)
icoLat = domeRad * math.sin(icoAngle)
self.latRad = domeRad.Value * math.cos(self.icoAngle)
latRad = domeRad * math.cos(icoAngle)
self.ang36 = math.radians(36.0)
ang36 = math.radians(36.0)
# Calculation all points of the icosahedron
# Calculation all points of the icosahedron
self.icoPts = []
icoPts = []
self.icoPts.append(Base.Vector(0.0, 0.0, domeRad.Value))
icoPts.append(Base.Vector(0.0, 0.0, domeRad))
for i in range(10):
for i in range(10):
self.icoCos = self.latRad * math.cos(i*self.ang36)
icoCos = latRad * math.cos(i*ang36)
self.icoSin = self.latRad * math.sin(i*self.ang36)
icoSin = latRad * math.sin(i*ang36)
if i%2 == 0:
if i%2 == 0:
self.icoPts.append(Base.Vector(self.icoSin, self.icoCos, self.icoLat))
icoPts.append(Base.Vector(icoSin, icoCos, icoLat))
else:
else:
self.icoPts.append(Base.Vector(self.icoSin, self.icoCos, -self.icoLat))
icoPts.append(Base.Vector(icoSin, icoCos, -icoLat))
self.icoPts.append(Base.Vector(0.0, 0.0, -domeRad.Value))
icoPts.append(Base.Vector(0.0, 0.0, -domeRad))
# 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 = self.icoPts[9]
thirdPt = icoPts[9]
thirdEdge = Part.makeLine(self.icoPts[0],thirdPt)
thirdEdge = Part.makeLine(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,self.icoPts[j])
firstEdge = Part.makeLine(thirdPt,icoPts[j])
secEdge = Part.makeLine(self.icoPts[j],self.icoPts[0])
secEdge = Part.makeLine(icoPts[j],icoPts[0])
triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
triFace = Part.Face(triWire)
triFace = Part.Face(triWire)
self.icoFaces.append(triFace)
icoFaces.append(triFace)
# Part.show(triFace)
# Part.show(triFace)
makeFreqFaces(self.icoPts[j], self.icoPts[0], thirdPt, ny)
makeFreqFaces(icoPts[j], icoPts[0], thirdPt, ny)
thirdEdge = Part.makeLine(self.icoPts[0],self.icoPts[j])
thirdEdge = Part.makeLine(icoPts[0],icoPts[j])
thirdPt = self.icoPts[j]
thirdPt = icoPts[j]
thirdPt = self.icoPts[9]
thirdPt = icoPts[9]
secPt = self.icoPts[10]
secPt = 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,self.icoPts[j])
firstEdge = Part.makeLine(thirdPt,icoPts[j])
secEdge = Part.makeLine(self.icoPts[j],secPt)
secEdge = Part.makeLine(icoPts[j],secPt)
triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
triFace = Part.Face(triWire)
triFace = Part.Face(triWire)
self.icoFaces.append(triFace)
icoFaces.append(triFace)
#Part.show(triFace)
#Part.show(triFace)
makeFreqFaces(self.icoPts[j], secPt, thirdPt, ny)
makeFreqFaces(icoPts[j], secPt, thirdPt, ny)
thirdPt = secPt
thirdPt = secPt
secPt = self.icoPts[j]
secPt = icoPts[j]
thirdEdge = Part.makeLine(secPt,thirdPt)
thirdEdge = Part.makeLine(secPt,thirdPt)
thirdPt = self.icoPts[10]
thirdPt = icoPts[10]
thirdEdge = Part.makeLine(self.icoPts[11],thirdPt)
thirdEdge = Part.makeLine(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,self.icoPts[j])
firstEdge = Part.makeLine(thirdPt,icoPts[j])
secEdge = Part.makeLine(self.icoPts[j],self.icoPts[11])
secEdge = Part.makeLine(icoPts[j],icoPts[11])
triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
triFace = Part.Face(triWire)
triFace = Part.Face(triWire)
self.icoFaces.append(triFace)
icoFaces.append(triFace)
#Part.show(triFace)
#Part.show(triFace)
makeFreqFaces(self.icoPts[j], self.icoPts[11], thirdPt, ny)
makeFreqFaces(icoPts[j], icoPts[11], thirdPt, ny)
thirdEdge = Part.makeLine(self.icoPts[11],self.icoPts[j])
thirdEdge = Part.makeLine(icoPts[11],icoPts[j])
thirdPt = self.icoPts[j]
thirdPt = icoPts[j]
# Shell of a corresponding icosahedron
# Shell of a corresponding icosahedron
newShell = Part.Shell(self.icoFaces)
newShell = Part.Shell(icoFaces)
#Part.show(newShell)
#Part.show(newShell)
# Shell of the geodesic dome
# Shell of the geodesic dome
#self.domeShell = Part.Shell(self.domeFaces)
#domeShell = Part.Shell(domeFaces)
#Part.show(self.domeShell)
#Part.show(domeShell)
obj.Shape = Part.Shell(self.domeFaces)
return Part.Shell(domeFaces)
# Shere with radius of geodesic dome for debugging purposes
# Shere with radius of geodesic dome for debugging purposes
testSphere = Part.makeSphere(domeRad.Value)
# testSphere = Part.makeSphere(domeRad)
#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:35, 8 March 2019

Other languages:

Macro Geodesic Dome

Description
This macro creates a geodesic dome

Macro version: 01.00
Last modified: 2015-01-04
Author: Ulrich Brammer
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.

File:Geodesic macro.png

Installation

Save the following script as MacroGeodesicDome.py to your macro directory.

Script

MacroGeodesicDome.py

# -*- coding: utf-8 -*-

# ************************************************************************
# * 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

def makeDomeShape(domeRad, ny):
    #semi-global variables
    a = 0 #Strutlength of underlying icosahedron:
    icoFaces = [] # collects faces of the underlying icosahedron
    domeFaces = [] # collects the faces of the geodesic dome
    
    def makeFreqFaces(fPt, sPt, thPt, ny = 1):
        # makes the geodesic dome faces out of the points of an
        # icosahedron triangle
        b = 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)
            kSecPt = fPt + growVec * (k+1.0)
            dSecPt = Base.Vector(kSecPt.x, kSecPt.y, kSecPt.z)
            dSecPt = dSecPt.normalize().multiply(domeRad)
            # 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)
                secPt = kSecPt + crossVec *(l+0.0)
                dSecPt =secPt.normalize().multiply(domeRad)
                thirdPt = kThirdPt + crossVec *(l+0.0)
                dThirdPt = thirdPt.normalize().multiply(domeRad)
                #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)
                    domeFaces.append(triFace)
                    #Part.show(triFace)
                
                oThirdPt = thirdPt
                doThirdPt = oThirdPt.normalize().multiply(domeRad)
                # 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)
                domeFaces.append(triFace)
                #Part.show(triFace)
    
        
    a=(4.0*domeRad)/math.sqrt(2.0*math.sqrt(5.0)+10.0) 
    
    # icoAngle: angle of vertices of icosahedron points 
    # not a north or south pole
    icoAngle = math.atan(0.5)
    
    icoLat = domeRad * math.sin(icoAngle)
    latRad = domeRad * math.cos(icoAngle)
    ang36 = math.radians(36.0)
    
    # Calculation all points of the icosahedron
    icoPts = []
    icoPts.append(Base.Vector(0.0, 0.0, domeRad))
    
    for i in range(10):
        icoCos = latRad * math.cos(i*ang36)
        icoSin = latRad * math.sin(i*ang36)
        if i%2 == 0:
            icoPts.append(Base.Vector(icoSin, icoCos, icoLat))
        else:
            icoPts.append(Base.Vector(icoSin, icoCos, -icoLat))
    
    icoPts.append(Base.Vector(0.0, 0.0, -domeRad))
    
    # making the faces of the icosahedron
    
    
    thirdPt = icoPts[9]
    thirdEdge = Part.makeLine(icoPts[0],thirdPt)
    for i in range(5):
        j = i*2+1
        firstEdge = Part.makeLine(thirdPt,icoPts[j])
        secEdge = Part.makeLine(icoPts[j],icoPts[0])
        triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
        triFace = Part.Face(triWire)
        icoFaces.append(triFace)
        # Part.show(triFace)
        makeFreqFaces(icoPts[j], icoPts[0], thirdPt, ny)
        
        thirdEdge = Part.makeLine(icoPts[0],icoPts[j])
        thirdPt = icoPts[j]
        
    thirdPt = icoPts[9]
    secPt = icoPts[10]
    thirdEdge = Part.makeLine(secPt,thirdPt)
    
    for i in range(10):
        j = i+1
        firstEdge = Part.makeLine(thirdPt,icoPts[j])
        secEdge = Part.makeLine(icoPts[j],secPt)
        triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
        triFace = Part.Face(triWire)
        icoFaces.append(triFace)
        #Part.show(triFace)
        makeFreqFaces(icoPts[j], secPt, thirdPt, ny)
    
        thirdPt = secPt	
        secPt = icoPts[j]	
        thirdEdge = Part.makeLine(secPt,thirdPt)
    
    
    thirdPt = icoPts[10]
    thirdEdge = Part.makeLine(icoPts[11],thirdPt)
    for i in range(5):
        j = i*2+2
        firstEdge = Part.makeLine(thirdPt,icoPts[j])
        secEdge = Part.makeLine(icoPts[j],icoPts[11])
        triWire = Part.Wire([firstEdge, secEdge, thirdEdge])
        triFace = Part.Face(triWire)
        icoFaces.append(triFace)
        #Part.show(triFace)
        makeFreqFaces(icoPts[j], icoPts[11], thirdPt, ny)
        
        thirdEdge = Part.makeLine(icoPts[11],icoPts[j])
        thirdPt = icoPts[j]
    
    # Shell of a corresponding icosahedron	
    newShell = Part.Shell(icoFaces)
    #Part.show(newShell)
    
    # Shell of the geodesic dome
    #domeShell = Part.Shell(domeFaces)
    #Part.show(domeShell)
    return Part.Shell(domeFaces)
    
    # Shere with radius of geodesic dome for debugging purposes
    # testSphere = Part.makeSphere(domeRad)
    #Part.show(testSphere)


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

Get the code from Github here!