1575 lines
59 KiB
Python
1575 lines
59 KiB
Python
# -*- 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 <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, 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 + 3)
|
|
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", "2500 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 + 2)
|
|
|
|
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", "45 mm")
|
|
|
|
self.gridLayout.addWidget(self.strutWidthLE, 5, 1, 1, 1)
|
|
self.strutHeightLE = FCUi.createWidget("Gui::InputField")
|
|
self.strutHeightLE.setObjectName("strutHeightLE")
|
|
self.strutHeightLE.setProperty("text", "45 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 a geodesic dome.\n"
|
|
"X-Y-symmetry-plane 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 += '<line x1="' + str(x1) + '" y1="' + str(y1)
|
|
lineSVG += '" x2="' + str(x2) + '" y2="' + str(y2)
|
|
lineSVG += strokeDef
|
|
if arrow:
|
|
# calculate arrow-points sX1, sY1, eX1, eY1, sX2, sY2, eX2, eY2
|
|
lLen = math.sqrt((x2-x1)**2 + (y2-y1)**2)
|
|
lDirX = (x2-x1)/lLen
|
|
lDirY = (y2-y1)/lLen
|
|
aOffX = -lDirY
|
|
aOffY = lDirX
|
|
lDirX *= 3.0
|
|
lDirY *= 3.0
|
|
|
|
lineSVG += '<line x1="' + str(x1+lDirX+aOffX) + '" y1="' + str(y1+lDirY+aOffY)
|
|
lineSVG += '" x2="' + str(x1) + '" y2="' + str(y1)
|
|
lineSVG += strokeDef
|
|
lineSVG += '<line x1="' + str(x1+lDirX-aOffX) + '" y1="' + str(y1+lDirY-aOffY)
|
|
lineSVG += '" x2="' + str(x1) + '" y2="' + str(y1)
|
|
lineSVG += strokeDef
|
|
|
|
lineSVG += '<line x1="' + str(x2-lDirX+aOffX) + '" y1="' + str(y2-lDirY+aOffY)
|
|
lineSVG += '" x2="' + str(x2) + '" y2="' + str(y2)
|
|
lineSVG += strokeDef
|
|
lineSVG += '<line x1="' + str(x2-lDirX-aOffX) + '" y1="' + str(y2-lDirY-aOffY)
|
|
lineSVG += '" x2="' + str(x2) + '" y2="' + str(y2)
|
|
lineSVG += strokeDef
|
|
return lineSVG
|
|
|
|
|
|
def addDim(self, x1, y1, x2, y2, dirX, dirY, dimText):
|
|
if dirX < -0.99:
|
|
dx1 = x1 - 5.0
|
|
dx2 = x1 - 5.0
|
|
dy2 = y2
|
|
dy1 = y1
|
|
# projection lines
|
|
p1x1 = x1
|
|
p1y1 = y1
|
|
p1x2 = x1 - 7.0
|
|
p1y2 = y1
|
|
p2x1 = x2
|
|
p2y1 = y2
|
|
p2x2 = x1 - 7.0
|
|
p2y2 = y2
|
|
# text position
|
|
tx1 = x1 - 7
|
|
ty1 = (y1 + y2)/2.0 + 5.0 / 2.0
|
|
tPos = 'end'
|
|
else:
|
|
dx1 = x1
|
|
dx2 = x2
|
|
dy2 = y2 - 5.0
|
|
dy1 = y1 - 5.0
|
|
# projection lines
|
|
p1x1 = x1
|
|
p1y1 = y1
|
|
p1x2 = x1
|
|
p1y2 = y1 - 7.0
|
|
p2x1 = x2
|
|
p2y1 = y2
|
|
p2x2 = x2
|
|
p2y2 = y2 - 7.0
|
|
# text position
|
|
tx1 = (x1 + x2) / 2.0
|
|
ty1 = y1 - 7.0
|
|
tPos = 'center'
|
|
|
|
|
|
viewDim = self.doc.addObject('Drawing::FeatureView','Dim_'+ dimText)
|
|
viewDim.ViewResult = '<g >\n'
|
|
viewDim.ViewResult += self.addSVGLine(p1x1, p1y1, p1x2, p1y2, False)
|
|
viewDim.ViewResult += self.addSVGLine(dx1, dy1, dx2, dy2, True)
|
|
viewDim.ViewResult += self.addSVGLine(p2x1, p2y1, p2x2, p2y2, False)
|
|
viewDim.ViewResult += '\n</g>\n'
|
|
viewDim.ViewResult += self.addSVGText(tx1, ty1, dimText, tPos)
|
|
|
|
self.Page.addObject(viewDim)
|
|
|
|
|
|
def addSVGText(self, x1, y1, theText, theAlign, fSize=None):
|
|
if fSize == None:
|
|
fSize = 5
|
|
if theAlign == 'end':
|
|
tAnchor = 'end'
|
|
elif theAlign == 'center':
|
|
tAnchor = 'middle'
|
|
else:
|
|
tAnchor = 'start'
|
|
textSVG = ''
|
|
textSVG += '<g transform="translate('
|
|
textSVG += str(x1) +',' + str(y1)
|
|
textSVG += ') rotate(0)">\n'
|
|
textSVG += '<text id="' + theText + '"\n'
|
|
textSVG += ' font-family="Sans"\n font-size="'
|
|
textSVG += str(fSize) + '"\n fill="#000000"\n'
|
|
textSVG += ' text-align="' + theAlign
|
|
textSVG += '"\n text-anchor="' + tAnchor + '">'
|
|
# textSVG += '<tspan x="0" dy="1em">'+ theText + '</tspan>\n'
|
|
textSVG += theText + '\n'
|
|
textSVG += '</text>\n</g>\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 += '<path d = "M ' + str(x1) + ' ' + str(y1) + 'A '
|
|
arcSVG += str(r) + ' ' + str(r) + ' 0 0 ' + sweep + ' '
|
|
arcSVG += str(x2) + ' ' + str(y2)
|
|
arcSVG += '" style="stroke:#000000;stroke-width:0.30;fill:none" />'
|
|
|
|
arcSVG += '<line x1="' + str(x1-1.0) + '" y1="' + str(y1+3.0)
|
|
arcSVG += '" x2="' + str(x1) + '" y2="' + str(y1)
|
|
arcSVG += strokeDef
|
|
arcSVG += '<line x1="' + str(x1+1.0) + '" y1="' + str(y1+3.0)
|
|
arcSVG += '" x2="' + str(x1) + '" y2="' + str(y1)
|
|
arcSVG += strokeDef
|
|
|
|
if sweep == '1':
|
|
cx = x1 - r
|
|
cy = y1
|
|
lLen = math.sqrt((x2-cx)**2 + (y2-cy)**2)
|
|
aOffX = (x2-cx)/lLen
|
|
aOffY = (y2-cy)/lLen
|
|
lDirX = -aOffY * 3.0
|
|
lDirY = aOffX * 3.0
|
|
else:
|
|
cx = x1 + r
|
|
cy = y1
|
|
lLen = math.sqrt((x2-cx)**2 + (y2-cy)**2)
|
|
aOffX = (x2-cx)/lLen
|
|
aOffY = (y2-cy)/lLen
|
|
lDirX = aOffY * 3.0
|
|
lDirY = -aOffX * 3.0
|
|
|
|
arcSVG += '<line x1="' + str(x2-lDirX+aOffX) + '" y1="' + str(y2-lDirY+aOffY)
|
|
arcSVG += '" x2="' + str(x2) + '" y2="' + str(y2)
|
|
arcSVG += strokeDef
|
|
arcSVG += '<line x1="' + str(x2-lDirX-aOffX) + '" y1="' + str(y2-lDirY-aOffY)
|
|
arcSVG += '" x2="' + str(x2) + '" y2="' + str(y2)
|
|
arcSVG += strokeDef
|
|
return arcSVG
|
|
|
|
def addArcDim(self, cx, cy, ang, r, sweep, dimText):
|
|
# sweep is SVG-sweep-flag '0' or '1'
|
|
if sweep == '1':
|
|
x1 = cx + r
|
|
x2 = cx + r*math.cos(ang)
|
|
y2 = cy + r*math.sin(ang)
|
|
px2 = cx + (r+2.0)*math.cos(ang)
|
|
py2 = cy + (r+2.0)*math.sin(ang)
|
|
tx1 = cx + (r+4.0)*math.cos(ang * 0.95)
|
|
ty1 = cy + (r+4.0)*math.sin(ang * 0.95)
|
|
tPos = 'start'
|
|
else:
|
|
x1 = cx - r
|
|
x2 = cx - r*math.cos(ang)
|
|
y2 = cy + r*math.sin(ang)
|
|
px2 = cx - (r+2.0)*math.cos(ang)
|
|
py2 = cy + (r+2.0)*math.sin(ang)
|
|
tx1 = cx - (r+4.0)*math.cos(ang * 0.95)
|
|
ty1 = cy + (r+4.0)*math.sin(ang * 0.95)
|
|
tPos = 'end'
|
|
|
|
viewDim = self.doc.addObject('Drawing::FeatureView','Dim_'+ dimText)
|
|
viewDim.ViewResult = '<g >\n'
|
|
viewDim.ViewResult += self.addSVGArc(x1, cy, x2, y2, r, sweep)
|
|
viewDim.ViewResult += self.addSVGLine(cx, cy, px2, py2, False)
|
|
viewDim.ViewResult += '\n</g>\n'
|
|
viewDim.ViewResult += self.addSVGText(tx1, ty1, dimText, tPos)
|
|
self.Page.addObject(viewDim)
|
|
|
|
|
|
|
|
|
|
|
|
class Strut(object):
|
|
''' This defines a strut class with a shape, a name and an annotation vertex'''
|
|
def __init__(self, strutShape, strutName, aPt, pDir):
|
|
self.Shape = strutShape
|
|
self.sName = strutName
|
|
self.annoPt = aPt # here we can add an annotation to a strut
|
|
self.proDir = pDir # projection Direction for strut Drawing
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Dome(object):
|
|
def __init__(self, domeRad_str, ny, tBands, strH, strW):
|
|
self.domeRad = FreeCAD.Units.parseQuantity(domeRad_str).Value
|
|
self.domeRadQuant = domeRad_str
|
|
print (" Dome Radius: ", self.domeRad, " String: ", domeRad_str)
|
|
self.ny = ny
|
|
if self.ny == 0:
|
|
self.ny = 1
|
|
self.totalBands = tBands # Number of rings of triangles making up the dome
|
|
if self.totalBands == 0:
|
|
self.totalBands = 3
|
|
# totalBands >= 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() |